Skip to content

refactor(sql-fs): centralize sandbox fencing policy - #274

Merged
Hazzng merged 3 commits into
mainfrom
refactor/sandbox-fencing-cte
Oct 19, 2026
Merged

Hazzng merged 3 commits into
mainfrom
refactor/sandbox-fencing-cte

Conversation

@Hazzng

@Hazzng Hazzng commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

Why

Five composite filesystem operations duplicated the sandbox fence policy. Share that policy while preserving the executed SQL, lock order, transaction context, and statement counts.

What changed

  • Keep the fence policy in sandbox.ts and use lazy SQL fragments in namespace operations.
  • Add Postgres regression coverage for stale writes, transaction context, hardlinks, and observed lock waits under READ COMMITTED and REPEATABLE READ. Extend the architecture checker to reject copied policy and raw SQL access in its consumers.
  • Fix verify helper SIGPIPE failures, report missing server builds, and add a patch changeset.

Scope

  • Postgres fencing and its verification tools.
  • No API contract, schema, or dependency changes.

Tradeoffs

Keep context setup inline. A separate context query adds statements and changes how a mismatched existing sandbox context behaves.

Blast Radius

Filesystem mutations share one fence builder, so a policy regression could affect several operations. SQL equivalence checks and real Postgres tests cover the preserved behavior.

Verification

  • pnpm check passed with 2,334 unit tests, both SDK checks, and builds.
  • pnpm verify:architecture passed with 279/279 integration tests and zero skips. Contracts, live SDKs, worker failures, stream finalization, input budgets, and tenant isolation passed.
  • The verify stack passed 41 journey assertions and the cross-client filesystem drive. Fresh correctness/security and code quality reviews found no blockers.

…octor

`suite_names | grep -qx` let grep exit on the first match, so suite_names died
with SIGPIPE and pipefail rejected `suite integration` every time on bash 3.2.
Doctor's `find | head -3` had the same latent failure on large trees and aborted
silently when dist/api/server.js was missing. Capture output before reading it,
report a missing build explicitly, and use explicit empty SERVER_ENV resets.
Five composite statements in namespace.ts each carried a copy of the epoch
acceptance, version advance, and epoch publication CTEs. fenceAndAdvance and the
new compositeFenceAndAdvance now share one private fenceCtes in sandbox.ts and
differ only in the ctx projection. Executed SQL, parameters, lock ordering, and
statement counts are unchanged.

A real-Postgres suite pins statement counts, caught-ESTALE-then-commit for every
composite and for ingest, the epoch fallback, mismatched RLS context, hardlinks,
and observed advisory-lock waits under READ COMMITTED and REPEATABLE READ.
check:architecture rejects fence policy or raw SQL access in namespace.ts and
ingest.ts.
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: d9fce945-ee71-4e48-a3a0-a68f3de31cec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 12 files

You’re at about 94% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/check-architecture-boundaries.mjs">

<violation number="1" location="scripts/check-architecture-boundaries.mjs:51">
P3: This generic pattern rejects unrelated version counters, not only `sandboxes.version` advancement. Scope the match to a `sandboxes` update or use SQL-aware matching so namespace and ingest queries do not need workarounds.</violation>

<violation number="2" location="scripts/check-architecture-boundaries.mjs:62">
P2: Assignment destructuring bypasses this raw-SQL check. Handle assignment-pattern destructuring and validate its source type before allowing the extracted `unsafe` or `file` capability.</violation>
</file>

<file name="scripts/check-architecture-boundaries.test.mjs">

<violation number="1" location="scripts/check-architecture-boundaries.test.mjs:211">
P2: This assertion relies on an undocumented filesystem traversal order. Sort the diagnostics before comparing them, or make checker output ordering deterministic, to prevent platform-dependent test failures.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

} else if (ast.isElementAccessExpression(node) && ast.isStringLiteral(node.argumentExpression)) {
receiver = node.expression;
name = node.argumentExpression.text;
} else if (ast.isBindingElement(node) && ast.isObjectBindingPattern(node.parent)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Assignment destructuring bypasses this raw-SQL check. Handle assignment-pattern destructuring and validate its source type before allowing the extracted unsafe or file capability.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/check-architecture-boundaries.mjs, line 62:

<comment>Assignment destructuring bypasses this raw-SQL check. Handle assignment-pattern destructuring and validate its source type before allowing the extracted `unsafe` or `file` capability.</comment>

<file context>
@@ -44,6 +44,40 @@ for (const importer of [
+	} else if (ast.isElementAccessExpression(node) && ast.isStringLiteral(node.argumentExpression)) {
+		receiver = node.expression;
+		name = node.argumentExpression.text;
+	} else if (ast.isBindingElement(node) && ast.isObjectBindingPattern(node.parent)) {
+		receiver = node.parent;
+		const property = node.propertyName ?? node.name;
</file context>

});
const diagnostics = checkArchitectureBoundaries(root).filter(({ code }) => code === "FENCE_POLICY_OWNER");
assert.deepEqual(
diagnostics.map(({ file, line }) => [file, line]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: This assertion relies on an undocumented filesystem traversal order. Sort the diagnostics before comparing them, or make checker output ordering deterministic, to prevent platform-dependent test failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/check-architecture-boundaries.test.mjs, line 211:

<comment>This assertion relies on an undocumented filesystem traversal order. Sort the diagnostics before comparing them, or make checker output ordering deterministic, to prevent platform-dependent test failures.</comment>

<file context>
@@ -188,3 +188,112 @@ it("permits literal non-worker imports and rejects indirect scope method calls",
+	});
+	const diagnostics = checkArchitectureBoundaries(root).filter(({ code }) => code === "FENCE_POLICY_OWNER");
+	assert.deepEqual(
+		diagnostics.map(({ file, line }) => [file, line]),
+		[
+			["src/sql-fs/dialects/postgres/ingest.ts", 3],
</file context>
Suggested change
diagnostics.map(({ file, line }) => [file, line]),
diagnostics.toSorted((a, b) => a.file.localeCompare(b.file) || a.line - b.line).map(({ file, line }) => [file, line]),

"src/sql-fs/dialects/postgres/namespace.ts",
"src/sql-fs/dialects/postgres/ingest.ts",
]);
const fencePolicyStatements = [/\bapp\.sandbox_epoch\b/i, /\bversion\s*=\s*(?:\w+\.)?version\s*\+/i];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This generic pattern rejects unrelated version counters, not only sandboxes.version advancement. Scope the match to a sandboxes update or use SQL-aware matching so namespace and ingest queries do not need workarounds.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/check-architecture-boundaries.mjs, line 51:

<comment>This generic pattern rejects unrelated version counters, not only `sandboxes.version` advancement. Scope the match to a `sandboxes` update or use SQL-aware matching so namespace and ingest queries do not need workarounds.</comment>

<file context>
@@ -44,6 +44,40 @@ for (const importer of [
+	"src/sql-fs/dialects/postgres/namespace.ts",
+	"src/sql-fs/dialects/postgres/ingest.ts",
+]);
+const fencePolicyStatements = [/\bapp\.sandbox_epoch\b/i, /\bversion\s*=\s*(?:\w+\.)?version\s*\+/i];
+
+function forbiddenSqlApiAccess(node, checker) {
</file context>

@Hazzng

Hazzng commented Oct 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@Hazzng

Hazzng commented Oct 18, 2026

Copy link
Copy Markdown
Owner Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T08:18:11.592842Z 0ae2ea4 Manual request
🔒 Security Review ✅ Completed 2026-10-18T08:19:05.305381Z 0ae2ea4 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 0ae2ea4aa9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 0ae2ea4aa9

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@Hazzng
Hazzng merged commit 1154c16 into main Oct 19, 2026
16 checks passed
@Hazzng
Hazzng deleted the refactor/sandbox-fencing-cte branch October 19, 2026 11:10
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