feat(estate-safety-kit): canonical vendored source for cross-repo safety helpers - #276
Merged
Conversation
…ety helpers Three security-relevant helpers were each written correctly once, then written AGAIN independently elsewhere in the estate with no code sharing, because there was nowhere shared to put the fix: - isSafeHttp (URL scheme allowlist / click-XSS guard): socioprophet#477 (app-vue), copy-pasted into socioprophet#550 (client-vue) rather than shared, since the two Vue packages don't share a workspace. - mintId (CSPRNG id minting, replacing hash-of-own-inputs schemes that collide same-millisecond): prophet-platform#1070 (health-twin ids.ts + consult.ts), the same pattern independently re-derived for socioprophet#484 (bootProofRecord). - bounded_int (non-negative-int-typed fields are not size-bounded when ints are arbitrary precision): prophet-platform#1067/#1071/#1118 (compute-gateway's exhaust guard), never generalized even to the sibling app nugget-extractor in the same repo. This follows the estate's existing vendoring convention (SHA-pinned tarball + PROVENANCE, as in prophet-platform's revendor_engine.py / assert_vendored_engine_marker.py, and the schemas/PROVENANCE.md pattern in apps/compute-gateway) rather than standing up a new npm/PyPI registry surface for three files. See estate-safety-kit/PROVENANCE.md for the full contract: consumers copy the file verbatim, record a PROVENANCE.txt with the source commit SHA, and run tools/check_vendored_safety_kit.py to prove byte-identity rather than trust a comment. 65 JS tests (node:test, zero dependencies) + 20 Python tests (pytest), all passing locally. Checker script smoke-tested against both a matching and a deliberately-drifted copy. New shared-infrastructure pattern — held for human review of the vendoring convention, not just the code.
… vendoring The canonical file docstrings said "See ../PROVENANCE.md", a path that is only valid inside this repo — once a consumer vendors the file verbatim, that relative path is wrong wherever it lands. Point at the repo-qualified location instead so the comment stays correct in every vendored copy. Also corrected the bounded_int.py citation: PR #1104 (found while drafting) is prophet-platform's GitHub Actions SHA-pinning PR, unrelated to the exhaust guard — the actual chain is #1067 (introduced) -> #1071 (open door found) -> #1118 (this fix). Caught before anyone reviewed it; not relying on an unverified citation in a PR body.
mdheller
pushed a commit
to SocioProphet/socioprophet
that referenced
this pull request
Aug 3, 2026
…test glob This file was added a few commits ago on this branch as a copy-paste of app-vue's url-safe.ts (same defect class, same fix) because the two Vue packages don't share a workspace. That duplication is exactly what SourceOS-Linux/sourceos-spec#276 exists to close: repoints this file to be a byte-identical vendored copy of estate-safety-kit/js/urlSafe.ts, with PROVENANCE.txt recording the source commit. app-vue's copy is being converted the same way on a separate PR (SocioProphet/socioprophet's chore/vendor-estate-safety-kit branch), since it already existed on master. No logic change — the vendored file is behavior-identical to what was already here (comments only differ). Also: vite.config.ts's vitest `include` was `src/__tests__/**/*.test.ts` only, so `npm test` never actually ran src/utils/urlSafe.test.ts, added earlier on this branch — the 12 tests pinning the allow/deny boundary existed but were never executed. Added a second glob scoped to src/utils/**/*.test.ts to fix that (deliberately not widened to src/**/*.test.ts — several other pre-existing test files elsewhere in this package are also out-of-glob with unverified pass/fail state; that is a separate, broader cleanup, flagged out-of-band rather than folded in here). Full suite after both changes: 124 files / 739 tests pass, including the 12 in urlSafe.test.ts.
This was referenced Aug 3, 2026
Merged
mdheller
pushed a commit
to SocioProphet/socioprophet
that referenced
this pull request
Aug 4, 2026
…test glob This file was added a few commits ago on this branch as a copy-paste of app-vue's url-safe.ts (same defect class, same fix) because the two Vue packages don't share a workspace. That duplication is exactly what SourceOS-Linux/sourceos-spec#276 exists to close: repoints this file to be a byte-identical vendored copy of estate-safety-kit/js/urlSafe.ts, with PROVENANCE.txt recording the source commit. app-vue's copy is being converted the same way on a separate PR (SocioProphet/socioprophet's chore/vendor-estate-safety-kit branch), since it already existed on master. No logic change — the vendored file is behavior-identical to what was already here (comments only differ). Also: vite.config.ts's vitest `include` was `src/__tests__/**/*.test.ts` only, so `npm test` never actually ran src/utils/urlSafe.test.ts, added earlier on this branch — the 12 tests pinning the allow/deny boundary existed but were never executed. Added a second glob scoped to src/utils/**/*.test.ts to fix that (deliberately not widened to src/**/*.test.ts — several other pre-existing test files elsewhere in this package are also out-of-glob with unverified pass/fail state; that is a separate, broader cleanup, flagged out-of-band rather than folded in here). Full suite after both changes: 124 files / 739 tests pass, including the 12 in urlSafe.test.ts.
mdheller
added a commit
to SocioProphet/socioprophet
that referenced
this pull request
Aug 4, 2026
* chore(app-vue): vendor url-safe.ts from estate-safety-kit, not a hand-maintained copy isSafeHttp was independently written here (#477) and then copy-pasted (not imported) into client-vue's utils/urlSafe.ts (#550) because the two Vue packages don't share a workspace — the exact kind of duplication SourceOS-Linux/sourceos-spec#276 exists to close. This repoints app-vue's copy to be a byte-identical vendored copy of estate-safety-kit/js/urlSafe.ts, with PROVENANCE.txt recording the source commit. client-vue's copy is being converted the same way on #550's branch, since that file doesn't exist on master yet. No behavior change: the vendored file is logic-identical to what was here (comments only differ — the canonical version documents both consumers and the vendoring contract instead of just this one). Confirmed with the existing test suite unchanged: 65/65 app-vue tests pass, including all 52 in url-safe.test.ts covering the allow/deny scheme boundary. * chore(app-vue): re-pin PROVENANCE.txt to the real sourceos-spec merge commit sourceos-spec#276 merged (squash) as 297c4e38 — the branch-head SHA this PROVENANCE.txt provisionally pinned no longer exists as a live ref. Verified byte-identical against the new pin before re-pinning (sha256 9493df8b... both sides), so this closes the provisional-pin TODO the file itself flagged rather than leaving it to rot. --------- Co-authored-by: Michael Heller <charles.peterson@socioprophet.ai>
mdheller
added a commit
to SocioProphet/socioprophet
that referenced
this pull request
Aug 4, 2026
) * fix(competitive-intel): scheme-allowlist BoardTable evidence links (XSS defense-in-depth) Adversarial review of #545 flagged: BoardTable.vue bound `:href` from `cell(...).evidence!.href` (competitiveBoardsApi JSON) with no scheme allowlist. `rel="noopener noreferrer"` is present but doesn't help — the JS in a `javascript:` href runs before a tab exists. Today's source is estate-internal (dashboard-bff/catalog-gateway JSON or bundled fixtures with hardcoded https://github.com/SocioProphet URLs), so this is defense-in-depth rather than an active exploit path. Same class of fix as #477 (Search.vue) — ported the helper to client-vue as `utils/urlSafe.ts` since app-vue's `services/url-safe.ts` isn't shared across the two packages. Unsafe evidence hrefs now render as plain text (label only, no link) instead of a live anchor. 10 test cases pin the allow/deny boundary. * chore(client-vue): vendor urlSafe.ts from estate-safety-kit; fix its test glob This file was added a few commits ago on this branch as a copy-paste of app-vue's url-safe.ts (same defect class, same fix) because the two Vue packages don't share a workspace. That duplication is exactly what SourceOS-Linux/sourceos-spec#276 exists to close: repoints this file to be a byte-identical vendored copy of estate-safety-kit/js/urlSafe.ts, with PROVENANCE.txt recording the source commit. app-vue's copy is being converted the same way on a separate PR (SocioProphet/socioprophet's chore/vendor-estate-safety-kit branch), since it already existed on master. No logic change — the vendored file is behavior-identical to what was already here (comments only differ). Also: vite.config.ts's vitest `include` was `src/__tests__/**/*.test.ts` only, so `npm test` never actually ran src/utils/urlSafe.test.ts, added earlier on this branch — the 12 tests pinning the allow/deny boundary existed but were never executed. Added a second glob scoped to src/utils/**/*.test.ts to fix that (deliberately not widened to src/**/*.test.ts — several other pre-existing test files elsewhere in this package are also out-of-glob with unverified pass/fail state; that is a separate, broader cleanup, flagged out-of-band rather than folded in here). Full suite after both changes: 124 files / 739 tests pass, including the 12 in urlSafe.test.ts. * fix(client-vue): widen vitest include — 6 real test files were never run The estate-safety-kit vendoring commit narrowly widened test.include to `['src/__tests__/**/*.test.ts', 'src/utils/**/*.test.ts']` to pick up urlSafe.test.ts specifically, and explicitly punted a broader fix: 6 other pre-existing, real (non-stub) test files sat outside BOTH globs — src/config/mesh.test.ts, src/features/contract-surfaces/contractSurfaces .test.ts, and 4 files under src/runtime-adapters/ (knowledgeGraphClient, ontologyClient, rescuedPlatformFeatures, routeRuntimeFeatures). `npm test`/CI never executed them. Same declared-but-unenforced shape as everything else this session has been closing — a test file existing is not the same as a test file running. Widened `include` to `src/**/*.test.ts`, replacing both narrower globs. Verified rather than assumed clean: - Full suite: 130 test files / 783 tests, all pass. - The 6 previously-orphaned files run in isolation: 6/6 files, 44/44 tests, all pass — nothing was actually stale or broken, they were just never executed. No test-content fixes were needed. - `vue-tsc --noEmit`: clean. The noisy ECONNREFUSED/AbortError console output during the full run is expected — live-adapter fallback tests intentionally hit an unreachable localhost:3000 to exercise the degraded path; vitest's own pass/fail accounting (783/783) is unaffected by it. * chore(client-vue): re-pin PROVENANCE.txt to the real sourceos-spec merge commit Same fix as #551 — sourceos-spec#276 merged (squash) as 297c4e38, the provisional branch-head pin is now dead. Verified byte-identical before re-pinning. --------- Co-authored-by: Michael Heller <charles.peterson@socioprophet.ai>
mdheller
added a commit
to SocioProphet/prophet-platform
that referenced
this pull request
Aug 4, 2026
…e fast-follow (#1336) ids.ts's mint-not-derive pattern (fixed here in #1070) was independently re-derived a third time for bootProofRecord in socioprophet's server contracts (#484) — no code shared either time. That duplication is what SourceOS-Linux/sourceos-spec#276 exists to close: a canonical estate-safety-kit/js/mintId.ts generalizing this exact pattern, with a `bytes` parameter so a caller can request this file's own stricter 256-bit width instead of forking the helper. Not converting ids.ts to a vendored copy in this change: the kit's default width is 128 bits, and a blind file-swap would silently narrow every id this service mints from 256 to 128 bits unless every call site (server.ts, consult.ts, invariants.ts) is updated in the same change to request 32 bytes explicitly. That's a real, reviewable refactor, not a comment. Tracked as prophet-platform#1335. 23/23 health-twin tests still pass — comment-only change.
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.
What this is
This session (2026-08-03) independently fixed the same three defect shapes in
three separate repos, with no code sharing between the fixes:
isSafeHttp— URL scheme allowlist against click-XSS. Written once insocioprophet-web/app-vue/src/services/url-safe.ts(socioprophet#477),
then copy-pasted (not imported) into
socioprophet-web/client-vue/src/utils/urlSafe.ts(socioprophet#550)
because the two Vue packages don't share a workspace.
mintId— CSPRNG id minting, replacing hash-of-own-inputs id schemesthat collide same-millisecond under load. Written in
apps/health-twin/src/ids.ts(prophet-platform#1070);
the same PATTERN (not the code) had to be independently re-derived for
bootProofRecordin socioprophet's server contracts(socioprophet#484).
pattern from compute-gateway's
engine.py(prophet-platform#1067 →
#1071 →
#1118),
never generalized even to the sibling app
nugget-extractorin the samerepo.
That's real technical debt: the same bug fixed multiple times instead of
once. This PR adds
estate-safety-kit/as the canonical, single source forall three, plus a vendoring contract so future consumers copy from one place
instead of re-deriving the fix again.
Why vendoring, not a package registry
The estate already has a proven pattern for cross-repo shared, trust-sensitive
content: SHA-pinned vendoring with a provenance record — not a package
registry. See
prophet-platform/tools/revendor_engine.py+tools/assert_vendored_engine_marker.py(the hellgraph engine tarball), andapps/compute-gateway/src/compute_gateway/schemas/PROVENANCE.md(vendoredzero-trust kernel schemas). A private npm/PyPI registry for three files would
be a new supply-chain surface, a publish pipeline, and a versioning burden
this estate has explicitly avoided elsewhere.
estate-safety-kit/PROVENANCE.mdin this PR is the full contract: consumers copy the file verbatim, record a
PROVENANCE.txtwith the source commit SHA, and runtools/check_vendored_safety_kit.py(byte-identity proof against the pinnedcommit — fetched from
raw.githubusercontent.comor a local--source-rootcheckout) instead of trusting a comment that says "kept in sync."
What's in it
js/urlSafe.ts+js/urlSafe.test.ts— merged from both existing copies(they'd converged to identical logic already; kept the more complete
comment). 53 tests,
node --test(zero dependencies), all passing.js/mintId.ts+js/mintId.test.ts— generalizes health-twin'sids.ts:default 128-bit width, with a
bytesparameter so a caller with astricter ratchet (health-twin's own 64-hex-everywhere invariant) can ask
for 256 bits from the same helper instead of forking it. 12 tests, all
passing.
py/bounded_int.py+py/test_bounded_int.py— generalizes_bad_nonneg_int/_MAX_NONNEG_INTfrom compute-gateway's exhaust guard,plus a bounded-string and aggregate-size-backstop sibling for the rest of
the same defect class. 20 tests,
pytest, all passing.tools/check_vendored_safety_kit.py— the checker consumers run in CI.Status
New shared-infrastructure pattern — held for human review of the vendoring
convention, not just the code. None of the three defects this closes are
newly discovered; every site listed above already has its own independent
fix merged. This PR's only effect once its consumer PR lands is that two
already-fixed files become vendored copies of one source instead of two
hand-maintained ones.
A consumer PR in
SocioProphet/socioprophetre-pointsapp-vue's andclient-vue'sisSafeHttpto vendor from this kit — it references this PRby number since it can't pin a merge commit that doesn't exist yet. Not
blocking merge order on that PR; noting the dependency explicitly.
Not requesting admin-merge on this one — asking for a human look at the
vendoring shape itself before anything estate-wide starts depending on it.
Update: the two consumer PRs in
SocioProphet/socioprophetare open:app-vue/src/services/url-safe.tsre-pointed to a vendored copy.client-vue/src/utils/urlSafe.tsre-pointed to a vendored copy (on thebranch that originally introduced it).
Both carry a provisional
PROVENANCE.txtpin at this PR's branch head(
78f5cf6) rather than a merge commit, since this PR isn't merged yet —each notes it needs re-pinning to the actual
maincommit once this lands.Both packages' full existing test suites pass unchanged against the
vendored copy (app-vue 65/65, client-vue 739/739).