Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add stage/pubtype restrictions to pub read api #988

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

tefkah
Copy link
Member

@tefkah tefkah commented Feb 25, 2025

Issue(s) Resolved

(not a ticket for this i believe)

Allow community admins to restrict Api access tokens to only read from an allowed list of stages/pub-types.

High-level Explanation of PR

Adds a new restriction for Pub.read api access tokens, allowing admins to specify "oh you can only read from these pub types/stages".

Some quirks:

Since we wanted to allow restricting both pub-types and stages, I was a bit stuck on how to do the selection UX.
Does only selecting one stage but no pub types allow you to read all pub types from that stage, or none, making the token effectively useless?

To solve this, I changed how the restriction selectors work: instead of having you select the things you want, you need to unselect the stages/pubtypes you do not want the token to have access to.

In addition, I added a "no stage" option to all the existing and new stage restrictions. While you could set a Pub create token to only allow creating pubs in certain stages, there was no option to allow pubs to be created without a stage. You can now explicitly allow this.

Test Plan

  1. Convince yourself of the accuracy of the tests.
  2. Create a token for two specific pubType in arcadia.
  3. Get all pubs from GET /api/v0/c/arcadia-research/pubs. Observe you only get back pubs from the pubtypes you specified.
  4. Get all pubs with one of the specific pubtypes from GET /api/v0/c/arcadia-research/pubs?pubTypeId=.... Observe you only get back pubs from the pubtype in the URL.
  5. Get all pubs with a pubtype that is outside of the thing you specified from GET /api/v0/c/arcadia-research/pubs?pubTypeId=<some other pubtypeid>. Observe you only get nothing.

Screenshots (if applicable)

Notes

@tefkah tefkah requested review from kalilsn, allisonking and 3mcd and removed request for allisonking February 26, 2025 11:44
@tefkah tefkah marked this pull request as ready for review February 26, 2025 11:44
Comment on lines +136 to +218
[ApiAccessType.read]: ({ value, onChange }) => {
const context = useContext(CreateTokenFormContext);

return (
<div className="flex flex-col gap-2">
<h3 className="font-semibold">Stages</h3>
<span className="text-xs text-muted-foreground">
Select the stages this token can read Pubs from
</span>
<MultiSelect
variant="inverted"
options={context.stages.allOptions}
defaultValue={
value === true || !value ? context.stages.allValues : value.stages
}
onValueChange={(val) => {
const allStagesSelected =
val.length === context.stages.allValues.length;

const allPubTypesSelected =
typeof value === "object" &&
value.pubTypes?.length === context.pubTypes.allValues.length;

if ((allStagesSelected || val.length === 0) && allPubTypesSelected) {
onChange(true);
return;
}

onChange({
stages:
val.length === 0
? context.stages.allValues
: (val as StagesId[]),
pubTypes:
typeof value === "object"
? value.pubTypes
: context.pubTypes.allValues,
});
}}
animation={0}
data-testid={`pub-${ApiAccessType.read}-stages-select`}
/>

<h3 className="font-semibold">Types</h3>
<span className="text-xs text-muted-foreground">
Select the types of Pubs this token can read
</span>
<MultiSelect
variant="inverted"
options={context.pubTypes.allOptions}
defaultValue={
value === true || !value ? context.pubTypes.allValues : value.pubTypes
}
onValueChange={(val) => {
const allPubTypesSelected =
val.length === context.pubTypes.allValues.length;

const allStagesSelected =
typeof value === "object" &&
value.stages?.length === context.stages.allValues.length;

if ((allStagesSelected || val.length === 0) && allPubTypesSelected) {
onChange(true);
return;
}

onChange({
pubTypes:
val.length === 0
? context.pubTypes.allValues
: (val as PubTypesId[]),
stages:
typeof value == "object"
? value.stages
: context.stages.allValues,
});
}}
animation={0}
data-testid={`pub-${ApiAccessType.read}-pubTypes-select`}
/>
</div>
);
},
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we add another restriction at some point, we should make these components a bit DRYer

props: ExtraParams
) => React.ReactNode;

return CorrectlyTypedExtraContraints;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -328,7 +414,7 @@ export const ConstraintFormFieldRender = ({
return (
<FormItemWrapper
dataTestId={`${scope}-${type}-checkbox`}
checked={Boolean(field.value)}
checked={typeof field.value === "object" ? "indeterminate" : Boolean(field.value)}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes the checkbox have a - in it instead of also looking like a checkmark when a restriction is selected

image

Comment on lines -1368 to +1375
pubTypeId?: PubTypesId;
stageId?: StagesId;
/**
* Multiple pubIds to filter by
*/
pubIds?: PubsId[];
pubTypeId?: PubTypesId[];
stageId?: StageConstraint[];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not reeeaally happy with having pubTypeId and stageId be singulars that accept arrays. mostly i did not want to introduce a bunch of noise to this PR, but i guess i already did

should i
a. change pubTypeId->pubTypeIds, same for stages
b. have both pubTypeId?: PubTypesId, pubTypeIds?: PubTypesIds[]
c. keep it like this

i think having pubIds separate from pubId makes sense, as they indicate a difference in the returned type (pubId returns a singular pub, while pubTypeIds returns an array)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant