test(export): pin the table and tool-param loss the sanitized export accepts - #6613
Conversation
…accepts #6591 enabled `redactOpaqueCredentialInputs` on the workflow export path, closing a real leak. It also made export lossy for tables and unauthoritative tool params, and nothing pinned that trade in either direction. Adds round-trip fixtures (an api block with two table sub-blocks, an agent block with a custom tool) plus assertions for the current loss, records the security/usability trade on the flag that governs it, and deletes a duplicate `sanitizeForExport` in credential-extractor that omitted the redaction flag and had zero production importers. No behavior change.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview Adds round-trip fixtures (API tables + custom-tool params) that assert whole Removes the unused duplicate Reviewed by Cursor Bugbot for commit b6a3b38. Configure here. |
Greptile SummaryThe PR documents the intentionally lossy workflow-export sanitization behavior, adds round-trip coverage for withheld table and custom-tool values, and removes an unused duplicate sanitizer wrapper.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/lib/workflows/operations/import-export-roundtrip.test.ts | Adds round-trip fixtures and non-vacuous assertions for table and custom-tool redaction; both previously reported test issues are resolved. |
| apps/sim/lib/workflows/credentials/credential-extractor.ts | Documents opaque credential redaction behavior and removes the unused duplicate export sanitizer. |
| apps/sim/lib/workflows/credentials/credential-extractor.test.ts | Updates sanitizer tests to use the production export option set explicitly. |
| apps/sim/lib/workflows/operations/export-workflow.ts | Relocates and expands the canonical export sanitization documentation without changing behavior. |
| apps/sim/app/api/v1/admin/folders/[id]/export/route.ts | Clarifies the behavioral difference between raw JSON and sanitized ZIP exports. |
| apps/sim/app/api/v1/workflows/[id]/export/route.ts | Clarifies that exported workflow envelopes are sanitized and may re-import with empty values. |
Reviews (4): Last reviewed commit: "test(export): make the env-ref leak swee..." | Re-trigger Greptile
The sweep asserted against a token the fixture no longer contained, so it passed vacuously. Both the fixture and the assertion now read one symbol, which is the only form that cannot drift. Also types the re-imported block lookup instead of casting through any.
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b6a3b38. Configure here.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b6a3b38. Configure here.
Summary
This PR intentionally changes no behavior. It pins an existing trade-off in place, documents it, and removes a footgun. No redaction logic is touched.
#6591 turned on
redactOpaqueCredentialInputsfor the workflow export path. That closed a real leak: a bearer token pasted into an API block's Headers cell, and secrets in custom tool params, were reaching the v1/v2 export APIs and the in-app Export as JSON in plaintext.Its unpriced cost shipped with it. An export/import round trip now returns API blocks with empty Headers and Query Params, and drops
{{ENV_VAR}}references inside table cells even though the same reference in apasswordfield survives. Nothing in the test suite described either side of that trade, so it could be flipped in either direction without anyone noticing — and an earlier audit did recommend reverting the flag.redactOpaqueCredentialInputs— which surfaces it governs, what is lost, why withholding beat per-cell heuristics, and the shape a future relaxation must takesanitizeForExportincredential-extractor.tsThe tests guard in both directions
Not just "redaction still works" — reverting the flag now fails loudly. Setting
redactOpaqueCredentialInputs: falseinjson-sanitizer.tsproduces exactly 4 failures:The first one is the point: it is executable proof that reverting the flag re-opens a secret leak. The other three pin the accepted cost, so anyone who decides the loss is unacceptable has to edit those expectations deliberately rather than delete the flag and ship.
The deleted duplicate was a real footgun
credential-extractor.tsexported its ownsanitizeForExportthat calledsanitizeWorkflowForSharingwithpreserveEnvVars: trueand notredactOpaqueCredentialInputs. It had zero production importers — every real caller uses the same-named but different function in@/lib/workflows/sanitization/json-sanitizer, which does pass the flag and returns a full envelope.Its only consumer was a test suite, which therefore described a configuration nothing runs. Two identically-named exports where one silently omits a redaction flag is exactly the shape of a future leak. The suite now passes the real option set explicitly, and
import-export-roundtripexercises the genuinesanitizeForExport, so the copy cannot drift unnoticed.Open question for the owner
This PR does not resolve the underlying tension, because it is a product decision, not an engineering one:
Is workflow export a faithful backup format, or a share-safe projection?
Those two goals conflict here and the answer decides any future change. Today the export path tries to be both and lands as a share-safe projection that people reasonably expect to be a backup. If it is a backup, the fix is a per-sub-block opt-in that fails closed for tables added later — never a wider default. If it is a share-safe projection, the current loss is correct and the gap is discoverability: nothing in the product or the logs tells a user their tables came back empty; they find out by re-importing.
Worth noting the first relaxation candidates are already visible in the new fixture —
api.params(query params) and response-shaping header tables are not credential sinks.Recommended next action: discoverability, not relaxation
Independent of how that question is answered, the concrete follow-up I'd recommend is telling the user what was withheld — surface a warning on export (and on import) that table sub-blocks and unauthoritative tool params came back empty and must be re-entered.
That is the right next step because it is the only option with no security trade: it does not widen what is exported by a single byte, so it cannot re-open the leak #6591 closed, and it works whichever answer the product question gets. It converts a silent loss into an informed one. Today a user discovers the loss by re-importing a workflow and finding empty Headers — which is also why this reached a release unnoticed.
Relaxing the redaction (a per-sub-block opt-in that fails closed) is the larger, riskier change and should wait on the product decision. Discoverability should not.
Type of Change
Testing
35/35 passing across
import-export-roundtrip,credential-extractor, andexport-workflow. Bidirectional guard verified by flipping the flag and confirming 4 failures, then restoring.bun run type-checkclean, biome clean.Checklist