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(gate)!: policies should affect visibility on introspection #963

Merged
merged 41 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
7067516
wip: cleanup 2
michael-0acf4 Jan 16, 2025
dc5628b
wip: cleanup + prep
michael-0acf4 Jan 16, 2025
42d5aef
feat: rassemble the metadata for visibility check
michael-0acf4 Jan 21, 2025
362e22b
fix: context
michael-0acf4 Jan 21, 2025
b1df722
fix: context
michael-0acf4 Jan 21, 2025
ae3dcf4
chore: merge main
michael-0acf4 Jan 22, 2025
c9d3082
feat: compute policies
michael-0acf4 Jan 22, 2025
b33f045
fix: include chain logic
michael-0acf4 Jan 22, 2025
bef0a7c
chore: more cleanups and refactor
michael-0acf4 Jan 22, 2025
71ad411
wip: make stripped version of typegraph
michael-0acf4 Jan 23, 2025
af50df2
feat: working poc
michael-0acf4 Jan 24, 2025
e3b04dc
fix: propagate parent if allow
michael-0acf4 Jan 24, 2025
c8e270e
wip: precalculate approach
michael-0acf4 Jan 27, 2025
1886038
wip: type emitter
michael-0acf4 Jan 28, 2025
17065b2
wip: type emitter 2
michael-0acf4 Jan 29, 2025
06c7e87
feat: base algo
michael-0acf4 Jan 29, 2025
0021e5e
feat: working poc 2
michael-0acf4 Jan 29, 2025
41e6783
fix: bad schema ref if scalar
michael-0acf4 Jan 29, 2025
d210a76
fix: name inconsistencies
michael-0acf4 Jan 30, 2025
87a3991
fix: root
michael-0acf4 Jan 30, 2025
61b25cb
fix: required kind (name can infer the underlying type)
michael-0acf4 Jan 30, 2025
f2d2041
fix: nested + missing arg
michael-0acf4 Jan 30, 2025
0b520b0
fix: optional and normal wrapper
michael-0acf4 Jan 31, 2025
eb37064
feat: handle union/either and circular ref
michael-0acf4 Jan 31, 2025
56a850e
feat: working poc 🎉
michael-0acf4 Jan 31, 2025
37cc3fd
feat: finalize rewrite on runtime side
michael-0acf4 Jan 31, 2025
e7bf8ab
fix: bad downstream ref name
michael-0acf4 Feb 1, 2025
bebce72
feat: add policy description
michael-0acf4 Feb 1, 2025
9426fb2
test: update snapshots
michael-0acf4 Feb 1, 2025
f9a4cff
fix: policy compute called many times
michael-0acf4 Feb 1, 2025
396a56b
fix: regenerated type on union
michael-0acf4 Feb 1, 2025
e36c4db
fix: emit adhoc object upon scalar on output union
michael-0acf4 Feb 3, 2025
a197d83
feat: ensure variant definition is emitted ahead
michael-0acf4 Feb 3, 2025
a47a7ec
test: feat
michael-0acf4 Feb 3, 2025
40ad445
fix: bad conditiona that enforces check on input
michael-0acf4 Feb 3, 2025
6649e67
fix: missed ALLOW & PASS rule on field if parent allows + test
michael-0acf4 Feb 4, 2025
988693f
Merge branch 'main' into policies-on-introspection
michael-0acf4 Feb 4, 2025
c847764
Merge branch 'main' into policies-on-introspection
michael-0acf4 Feb 5, 2025
68542fd
chore: cleanups
michael-0acf4 Feb 5, 2025
4000ec4
fix: bad logic on same level fields
michael-0acf4 Feb 5, 2025
6c1e678
Merge branch 'main' into policies-on-introspection
michael-0acf4 Feb 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
tmate_enabled:
type: boolean
description: |
Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate).
Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate).
This disables all but the test-full jobs.
required: false
default: false
Expand All @@ -20,7 +20,6 @@ on:
- synchronize
- ready_for_review


# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
Expand Down Expand Up @@ -305,6 +304,7 @@ jobs:
tests/runtimes/wasm_reflected/*.ts \
tests/runtimes/python/*.ts \
tests/runtimes/substantial/common.ts \
tests/introspection/common.ts \
tests/e2e/self_deploy/self_deploy.ts \
tests/e2e/published/*.ts \
tests/metagen/typegraphs/metagen.ts \
Expand Down
4 changes: 2 additions & 2 deletions src/typegate/src/engine/computation_engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,12 @@ export class ComputationEngine {
(lens as Array<Record<string, unknown>>).forEach((l, i) => {
// Objects are replaced by empty objects `{}`.
// It will be populated by child compute stages using values in `cache`.
l[field] = withEmptyObjects(res[i]);
(l ?? {})[field] = withEmptyObjects(res[i]);
});

// TODO
this.lenses[stageId] = lens.flatMap((l) =>
batcher([(l as Record<string, unknown>)[field]]) ?? []
batcher([((l ?? {})as Record<string, unknown>)[field]]) ?? []
);
}

Expand Down
83 changes: 47 additions & 36 deletions src/typegate/src/engine/planner/policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,31 +203,33 @@ export class OperationPolicies {
} // elif deny => already thrown
}

const res = await this.#checkStageAuthorization(
const resultsPerField = await this.#checkStageAuthorization(
stageId,
activeEffect,
getResolverResult,
);

switch (res.authorized) {
case "ALLOW": {
resolvedPolicyCachePerStage.set(stageId, "ALLOW");
continue;
}
case "PASS": {
resolvedPolicyCachePerStage.set(stageId, "PASS");
continue;
}
default: {
resolvedPolicyCachePerStage.set(stageId, res.authorized);
const policyNames = res.policiesFailed.map((operand) => ({
name: this.tg.policy(operand.index).name,
concernedField: operand.canonFieldName,
}));

throw new BadContext(
this.#getRejectionReason(stageId, activeEffect, policyNames),
);
for (const { fieldStageId, check } of resultsPerField) {
switch (check.authorized) {
case "ALLOW": {
resolvedPolicyCachePerStage.set(fieldStageId, "ALLOW");
continue;
}
case "PASS": {
resolvedPolicyCachePerStage.set(fieldStageId, "PASS");
continue;
}
default: {
resolvedPolicyCachePerStage.set(fieldStageId, check.authorized);
const policyNames = check.policiesFailed.map((operand) => ({
name: this.tg.policy(operand.index).name,
concernedField: operand.canonFieldName,
}));

throw new BadContext(
this.#getRejectionReason(fieldStageId, activeEffect, policyNames),
);
}
}
}
}
Expand All @@ -238,19 +240,19 @@ export class OperationPolicies {
effect: EffectType,
policiesData: Array<{ name: string; concernedField: string }>,
): string {
const getPath = (concernedField: string) => {
const getPath = () => {
if (stageId == EXPOSE_STAGE_ID) {
return [EXPOSE_STAGE_ID, concernedField].join(".");
return EXPOSE_STAGE_ID;
}
return [EXPOSE_STAGE_ID, stageId, concernedField].join(".");
return [EXPOSE_STAGE_ID, stageId].join(".");
};

const detailsPerPolicy = policiesData
.map(({ name, concernedField }) =>
.map(({ name }) =>
[
`policy '${name}'`,
`with effect '${effect}'`,
`at '${getPath(concernedField)}'`,
`at '${getPath()}'`,
].join(" ")
);
return `Authorization failed for ${detailsPerPolicy.join("; ")}`;
Expand Down Expand Up @@ -407,12 +409,16 @@ export class OperationPolicies {
getResolverResult: GetResolverResult,
) {
const selectedFields = this.#findSelectedFields(stageId);

const checkResults = [];
const policiesForStage = this.#stageToPolicies.get(stageId) ?? [];
const policies = [];
for (const { canonFieldName, indices } of policiesForStage) {
const policies = [];

// Note: canonFieldName is the field on the type (but not the alias if any!)
if (!selectedFields.includes(canonFieldName)) {
const selected = selectedFields.find(({ node }) =>
node == canonFieldName
);
if (!selected) {
continue;
}

Expand All @@ -433,25 +439,30 @@ export class OperationPolicies {
policies.push({ canonFieldName, index: actualIndex });
}
}

checkResults.push({
fieldStageId: selected.stageId,
check: await this.#composePolicies(
policies,
effect,
getResolverResult,
),
});
}

return await this.#composePolicies(
policies,
effect,
getResolverResult,
);
return checkResults;
}

#findSelectedFields(targetStageId: string) {
return this.orderedStageMetadata.map(({ stageId, node }) => {
const chunks = stageId.split(".");
const parent = chunks.slice(0, -1).join(".");
if (parent == "" && targetStageId == EXPOSE_STAGE_ID) {
return node;
return { stageId, node };
}

return targetStageId == parent ? node : null;
}).filter((name) => name != null);
return targetStageId == parent ? { stageId, node } : null;
}).filter((val) => val != null);
}

// for testing
Expand Down
Loading
Loading