Skip to content

feat(flowscript): secure project-scoped API and deployment boundaries (#651) - #665

Merged
Mihir-Rabari merged 6 commits into
Mihir-Rabari:devfrom
atharvashukla098-tech:feat/flowscript-tenant-isolation
Oct 19, 2026
Merged

Mihir-Rabari merged 6 commits into
Mihir-Rabari:devfrom
atharvashukla098-tech:feat/flowscript-tenant-isolation

Conversation

@atharvashukla098-tech

@atharvashukla098-tech atharvashukla098-tech commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

User description

Resolves #651

Summary of Changes

  • Cryptographic Project Identity: Enforced HMAC-SHA256 signatures (\x-project-signature\ / \x-gateway-signature) and signed Bearer tokens with fail-closed behavior if gateway secrets are unset (\GATEWAY_SECRET_MISSING).
  • Header Spoofing Prevention: Rejects forged project headers (\FORGED_PROJECT_HEADER) on identity conflict and validates project ID format (\INVALID_PROJECT_ID_FORMAT). Added \stripUntrustedProjectHeaders\ helper for edge gateway sanitization.
  • Request Tracing: Added \x-request-id\ support with UUID generation if missing, echoing on response headers and error envelopes.
  • Payload Limits: Enforced 1MB request body limit (\PAYLOAD_TOO_LARGE\ on 413).
  • Deployment Boundaries: Enforced flow name verification on deploy (\FLOW_NAME_MISMATCH) and cross-project version isolation (\VERSION_NOT_FOUND).
  • Standardized Error Envelope: Normalized all error responses to { statusCode, code, error, message, requestId }.
  • Test Suite: Added comprehensive unit test suite in \ enant_isolation.test.ts\ (13 tests passing).
  • Documentation: Updated \docs/flowscript/SECURITY.md\ and \docs/flowscript/API.md.

CodeAnt-AI Description

Make FlowScript runs retryable, cancellable, and isolated by project

What Changed

  • Transient integration failures retry with bounded backoff, and callers can inspect each step attempt.
  • Workers recover expired runs, while runs with possible non-idempotent side effects are marked uncertain instead of replayed. Runs can also be cancelled while queued or executing.
  • Idempotency keys prevent duplicate runs when clients repeat a request.
  • Project-scoped APIs reject forged identities and cross-project deployments; responses include request IDs and consistent error details, and request bodies are limited to 1 MB.

Impact

✅ Fewer transient flow failures
✅ Fewer duplicate external actions
✅ Blocked cross-project access

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 1915f9d Oct 19, 2026 · 10:15 10:16
✅ Reviewed your PR 051f432 Oct 17, 2026 · 15:34 15:40

@codeant-ai

codeant-ai Bot commented Oct 17, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Oct 17, 2026
Comment thread services/flowscript/src/server.ts Outdated
@codeant-ai

codeant-ai Bot commented Oct 17, 2026

Copy link
Copy Markdown

CodeAnt Nitpicks

3 code suggestions

1. The accepted missedTickPolicy is omitted from the trigger config, so skip and catch-up requests are silently stored without policy-specific behavior.

Incomplete implementation · services/flowscript/src/server.ts:345


2. The standardized error-code list omits NOT_IMPLEMENTED and DEPLOYMENT_NOT_FOUND, which these routes return, leaving clients without documented handling for those responses.

Api mismatch · docs/flowscript/API.md:104


3. Malformed JSON errors carry Fastify's FST_ERR_CTP_INVALID_JSON_BODY, which this preserves instead of returning the documented BAD_REQUEST code.

Api mismatch · services/flowscript/src/server.ts:194

@codeant-ai

codeant-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

CodeAnt PR Risk: Medium Risk

  • The PR needs attention before merging because existing databases retain the old run-status constraint and may reject transitions to dead_letter or uncertain.
  • The runtime retries retryable integration failures without requiring an idempotency key; timed-out calls are not aborted, so retries can repeat external side effects.
  • Trigger-creation exceptions, including database outages, are returned as 422 client errors rather than 500 server errors.

Assessed commit: 1915f9dfe104

@Mihir-Rabari

Copy link
Copy Markdown
Owner

Rebase request ⏰ — dev moved under you: #663 (schedule hardening, #656) just merged (merge commit 888c00a6ef), reworking services/flowscript/src/server.ts (trigger-config zod schema + enqueue path), which this PR also touches → GitHub now reports CONFLICTING.

Could you rebase onto dev and push? At the new head I'll run the full first review (project-scoped API / HMAC identity / deployment boundaries vs #651) and merge same-tick if green. Your CI at the current head is green (run 39045607450), so the rebase should re-run cleanly.

Suggested order for your stack: #664 first, then #665, then #666 last (it contains all three branches via merge commits, so it'll reduce to its own CI-job delta once the parents land).

— Hermes Agent, on behalf of @Mihir-Rabari

@Mihir-Rabari

Copy link
Copy Markdown
Owner

Quick re-ping @atharvashukla098-tech ⏰ — the rebase request above (~16:06Z) is ~3h unanswered, so bumping it once to keep #651 moving.

Also: your 16:30Z fix commit 82202b948 (missedTickPolicy / error-taxonomy / json-parser polish answering codeant) is noted and appreciated — I'll fold it into the full review at the rebased head, so no action lost.

Current state:

Suggested stack order remains 664 → 665 → 666 (rebasing on top of #664 avoids a second conflict pass). 🙌

@Mihir-Rabari

Copy link
Copy Markdown
Owner

👋 Friendly bump — still CONFLICTING against dev (head 82202b948a, including the missedTickPolicy / error-taxonomy / json-parser fix — credited for the future review). Suggested order: land #664 first, then rebase this one on the fresh tip; I'll run the full first review same-tick and merge on green. The 664 → 665 → 666 stack is queued behind it. 🙏

@Mihir-Rabari

Copy link
Copy Markdown
Owner

4th ping — rebase still owed (~7h). Still CONFLICTING with dev at 82202b948 (your 16:30Z codeant-fix commit is banked and will be credited at review — just fold it into the rebase). Stack order: #664 → #665 → #666. Push the rebased head and the machine will full-review same-tick and approve+merge on green CI. Stuck on the conflicts? Drop a note here. — Hermes Agent, on behalf of @Mihir-Rabari

…ff (#657)

- Preserve cancelled status in finishRun to prevent worker result overwrite
- Cap exponential backoff with jitter strictly at maxMs
- Abort worker execution if heartbeat detects lease loss (!hb.active)
- Document succeeded attempt status and backoff formula in EXECUTION.md
… (#651)

- Enforce cryptographic gateway signatures (HMAC-SHA256) and signed Bearer tokens
- Fail closed when gateway secret is missing
- Validate project ID format and reject forged project headers on identity conflict
- Add stripUntrustedProjectHeaders helper for edge gateway sanitization
- Enforce global 1MB payload bodyLimit mapping to PAYLOAD_TOO_LARGE
- Implement x-request-id correlation across request headers and error responses
- Standardize error envelope with statusCode, code, error, message, requestId
- Enforce flow name verification and project isolation on deploy
- Add comprehensive tenant isolation test suite and update documentation
@atharvashukla098-tech
atharvashukla098-tech force-pushed the feat/flowscript-tenant-isolation branch from 82202b9 to 1915f9d Compare October 19, 2026 10:15
@atharvashukla098-tech

Copy link
Copy Markdown
Collaborator Author

@Mihir-Rabari @hermes-agent Rebased eat/flowscript-tenant-isolation onto PR #664 (40a8a5e), resolved trigger column integration with #663, addressed all CodeAnt review feedback, and verified 100% test pass (238 passed, 0 failed) with clean typecheck and lint. Ready for review and merge.

@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Oct 19, 2026

@Mihir-Rabari Mihir-Rabari left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Review TL;DR — ✅ APPROVE

Reviewed head: 1915f9dfe1 (delta on top of merged #664 40a8a5e11a; full CI matrix green at this head; issues #651)

First review after the rebase — the 16:30Z Oct-17 polish commit (missedTickPolicy / error-taxonomy) is folded in and credited. This delta is a genuinely strong hardening pass.

✅ Strengths

  • Identity confusion closed: Bearer-token project vs caller-supplied x-project-id conflicts now 401 FORGED_PROJECT_HEADER (auth.ts), plus strict /^[a-zA-Z0-9_-]{1,128}$/ project-ID validation and trimmed signature handling.
  • Standardized error envelope everywhere (sendError: statusCode/code/error/message/requestId) + Fastify setErrorHandler mapping (FST_ERR_CTP_BODY_TOO_LARGE → 413 PAYLOAD_TOO_LARGE, invalid JSON → 400) — exactly the #651 envelope ask, and API.md now documents every code.
  • x-request-id propagation: accepts caller/edge IDs (≤128 chars) or generates UUIDv4, echoed via onSend + embedded in all error envelopes — trace correlation finally exists.
  • Global 1MB bodyLimit with 413 handling — the #651 input-limit ask.
  • Deploy boundaries enforced and classified: cross-project version deploy → 404 VERSION_NOT_FOUND; URL :name vs version flow-name mismatch → 400 FLOW_NAME_MISMATCH (project-scoped version lookup in store makes the cross-project case impossible to bypass).
  • stripUntrustedProjectHeaders exported for edge gateways (deletes x-project-id/x-project-signature/x-gateway-signature), documented in SECURITY.md.
  • SECURITY.md honestly re-baselined from "current blockers" to concrete enforced controls.

🔴 Blocking — none.

⚠️ Should fix (non-blocking follow-up)

  1. services/flowscript/src/server.ts trigger-create catch: infra failures (e.g. pg outage in createFlowTrigger) still classify as 422 TRIGGER_CREATION_FAILED — the codeant thread asked for 500 on internal errors. The cron/timezone/policy → 400 split is right; consider distinguishing DB/unique-constraint errors → 500 INTERNAL_SERVER_ERROR next pass. Same idea for the deploy catch's 422 DEPLOYMENT_FAILED.

💡 Nits

  • The /v1/flows/:name/runs/:id/cancel route still doesn't check :name against the run's flow (inherited from #664, noted there — intra-project only).

Tests ✅ — tenant_isolation.test.ts (584 lines) is the right shape: full 401 sweep across every project-scoped route, forged-header/invalid-HMAC/identity-conflict/fails-closed cases with exact code assertions, cross-project deploy + run + trigger isolation (list leaks nothing; get/patch/rotate/delete all 404 with owner data intact), request-id echo + UUID generation, and a real 1.2MB body → 413 test. Negative paths everywhere — not tautologies.

Prior feedback status

  • codeant server.ts:366 (DB outage → 422 misclassification) → partial (validation errors now 400; envelope + code stable; infra errors still 422 — see should-fix #1, non-blocking).
  • Banked 16:30Z commit (missedTickPolicy validation, error taxonomy) → addressed in this delta.

Acceptance criteria (#651): gateway identity hardening ✅ · forged/identity-conflict rejection ✅ · project-scoped authorization on publish/deploy/run/trigger/run-inspection ✅ · deploy :name validation ✅ · normalized error envelope ✅ · source/input limits ✅. Deferred (reasonable): per-user membership model (project-level gateway identity is the current design), versioned DB migrations.

Merging now — #666 (the CI-job + E2E layer) is next on the stack.

— Hermes Agent, reviewing on behalf of @Mihir-Rabari

@Mihir-Rabari
Mihir-Rabari merged commit 9a4230a into Mihir-Rabari:dev Oct 19, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants