[ENG-3564] map: upload the attack surface to Pulse behind an explicit --upload flag - #134
Merged
patchstackdave merged 2 commits intoAug 14, 2026
Conversation
|
Implements a clear opt-in 🎯 Quality: 100% Elite · 📦 Size: Medium 📈 This month: Your 67th PR — above team average · Averaging Excellent |
Contributor
Author
|
/review |
daniloradovic
approved these changes
Aug 14, 2026
Leg 2's client half. `map` described the app's surface and the server could receive one, but nothing sent
it, so per-site parameter pinning only ever worked on hand-fed data.
patchstack-connect map --upload
-> POST monitor/pulse/input-map/<site uuid>
-> "uploaded the attack surface (revision 1)" / "unchanged since revision 1" / a reported failure
Opt-in, never implied. This is the only path that transmits anything derived from source code, so it
takes an explicit flag rather than happening because a site UUID exists. With the flag the document goes
to Patchstack instead of stdout — printing a full structural document AND sending it is noise.
Fail-open by construction: every path returns an outcome instead of throwing, because this runs inside
someone's build. A 422 is reported as a schema mismatch by version ("update @patchstack/connect") rather
than retried or coerced — it means one side implements a different map schema, and guessing at
compatibility is exactly how a consumer misreads a document. `unchanged` is a first-class result: most
builds do not change the surface, and the server keeps one revision per distinct surface, not per deploy.
Disclosure, which is the part that must not lag the code: README and AGENT-INSTALL previously said `map`
"transmits nothing", which would have become false the moment this shipped. Both now state exactly what
`--upload` sends — route paths, parameter names, the dependency behind each sink, file/line locations —
and what it does not: no source code, no file contents, no environment variable values. Same file and
bullet as the pending tier-wording fix, so whichever lands second needs a trivial rebase.
Verified end to end against a local Pulse server rather than only with mocks: a real project's map
uploaded as revision 1, an unchanged rebuild reported unchanged, a new endpoint stored revision 2, rule
generation pinned `post.sql` and `post.q` from it, and the public rules endpoint served both. That run
also turned up a middleware gap on the server side (the ingest path was missing from the CSRF exemption
list) which every server-side feature test missed, because `postJson` bypasses CSRF.
12 upload tests; 940 total.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review point on the upload client: `{ result: 'stored' }` with no revision, or revision 0, was reported as
a success with `revision: 0`. That is not a state the server can be in, and announcing it would claim an
upload that cannot be pointed at afterwards — worse than reporting a failure.
A revision must now be a positive integer for either success result to be accepted; anything else is a
failure with the generic unexpected-response message. Covered for a missing revision, zero, and a
non-numeric one.
941 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
patchstackdave
force-pushed
the
davejong/eng-3564-connect-post-the-attack-surface-map-to-pulse-map-leg-2
branch
from
August 14, 2026 12:11
235c0ba to
9b2ee83
Compare
patchstackdave
deleted the
davejong/eng-3564-connect-post-the-attack-surface-map-to-pulse-map-leg-2
branch
August 14, 2026 12:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the loop between two halves that already existed:
mapdescribed the app's surface, the server can receive one, nothing sent it.Design calls
Opt-in, never implied. This is the only path that transmits anything derived from source code, so it takes an explicit flag rather than firing because a site UUID happens to exist. With the flag the document goes to Patchstack instead of stdout.
Fail-open by construction. Every path returns an outcome rather than throwing — this runs inside someone's build. A
422is reported as a schema mismatch by version ("update @patchstack/connect") rather than retried or coerced: it means the two sides implement different map schemas, and guessing at compatibility is exactly how a consumer misreads a document.unchangedis a first-class result, not a failure.Disclosure — the part that must not lag the code
README and AGENT-INSTALL both said
map"transmits nothing". That becomes false the moment this ships, so both now state exactly what--uploadsends (route paths, parameter names, the dependency behind each sink, file/line locations) and what it does not (no source code, no file contents, no env values).--persona hostilerun belongs against the published tarball at release.Verified end to end, not just with mocks
Against a local Pulse server, with a real project:
That run also found a bug the server-side tests could not: the ingest path was missing from the CSRF exemption list, so a real client got
419while every feature test passed (postJsonbypasses CSRF). Fixed on the saas branch.12 upload tests, 940 total, typecheck clean.