Skip to content

feat: template Slack webhook paths in the URL scrub (v0.1.2) - #3

Merged
victor-carv merged 2 commits into
mainfrom
feat/template-slack-webhook-url
Oct 16, 2026
Merged

victor-carv merged 2 commits into
mainfrom
feat/template-slack-webhook-url

Conversation

@victor-carv

Copy link
Copy Markdown
Member

What

A Slack incoming-webhook URL (https://hooks.slack.com/services/T…/B…/<secret>) carries its secret in the path. The undici instrumentation opens a client span for every fetch, so url.full / http.url would export it. This adds the Slack webhook shapes to TOKEN_PATH_TEMPLATES, so they are templated like the /apply/<token> paths already are:

  • /services/<a>/<b>/<secret> → /services/[webhook]
  • /triggers/<a>/<b>/<secret> → /triggers/[webhook]
  • /workflows/<a>/<b>/<secret> → /workflows/[webhook]

Anchored, case-insensitive, any run of /, exactly three segments. Mirrored in src/scrub-contract.json. package.json goes to 0.1.2 and dist/ is rebuilt (only url-path.js / url-path.d.ts change).

Why now: ACP's worker posts to a Slack webhook, and ACP refuses worker telemetry in code until this ships (carbon-acp#158).

Behaviour change to note for the release

The templates are host-agnostic (the contract is path-only, and the agent's layer-2 scrub repeats it). A non-Slack client or unrouted span whose path is /services|triggers|workflows/a/b/c is templated too. Spans with an http.route keep the route.

Known limits (documented in the README)

  • Log text (scrubMessage / scrubErrorText) strips userinfo, query and fragment but does not template token paths. This already held for /apply/<token>. Never log a webhook or token URL. A follow-up needs a layer-2 change as well.
  • A URL an app puts in an attribute outside the URL keys is not templated; apps must use redactKeys.
  • Non-normalised URLs (%2F, backslashes, dot segments) can leave a trailing segment. URLs from undici arrive normalised.

Tests

pnpm typecheck, pnpm test (978 pass) and pnpm build are clean, and the committed dist/ equals a fresh build. New cases cover url.full, http.url, http.target, url.path, event and link attributes, a query string, doubled slashes, upper case, a trailing path and a scheme-less //host, and check that none of the three segments appears anywhere in the exported span. Negatives: /services, /services/a/b, /servicesX/a/b/c (and the same for the other two). Removing the three entries makes 12 tests fail.

After the merge: tag v0.1.2 on the rebased merge SHA after checking its tree equals this head's tree, then update carbon-observability's contract copy and Alloy scrub, then bump ACP's pin.

QA Check Report

Risk level: LOW

No escalations: a written spec exists (observability platform plan, Phase 7 handoff), and the touched files are small (url-path.ts 69 lines, the test file 291 lines).

Spec discipline

  • Spec found: yes. codelittinc/carbon-backbone#825, tasks/observability-platform/phase-7-acp.md, and the Phase 7 handoff step 2 ("template hooks.slack.com/services/… in the span URL scrub, with a test").
  • Scope beyond the spec: the /triggers/ and /workflows/ Slack webhook shapes, added after the deploy/PII lens review found them untemplated. Same mechanism, same shape.

Complexity

  • Files touched: 8 (1 source file, 1 contract JSON, 2 test files, README, package.json, 2 generated dist files) | Decision points modified: 3 regex entries in one table | Cross-domain: no.
  • Rework signals: url-path.ts was last touched by the unrelated ./scrub entry work, not for this feature. The two commits here are the feature and its review fix.
  • Unhealthy files: none (4 commits in 90 days on url-path.ts, under 10).
  • Sustainable velocity: 175 insertions, 133 of them tests.

Test integrity

  • No existing test line was removed, skipped or loosened (0 deleted lines under src/tests).
  • New tests assert exact exported output and scan the serialised span for each secret segment. A mutation check removed the three entries: 12 tests failed, then the file was restored.

Dependency provenance

  • No dependency added or changed. package.json changes only the version, 0.1.1 to 0.1.2.

Validation gaps

  • Known and ruled (R263): log-text scrubbing (scrubMessage / scrubErrorText) does not template token paths. The gap already existed for /apply/<token>. It is documented in the README, and a follow-up needs a layer-2 Alloy change.
  • Known and ruled (R265): non-normalised URLs (%2F, backslashes, dot segments) can leave a trailing segment. Auto-instrumented URLs come from undici already normalised.

AI-specific concerns

  • Duplicated logic: the three entries repeat one shape (three segments, one replacement). That matches how TOKEN_PATH_TEMPLATES and the contract JSON are written, which the contract test requires to stay in the same order.
  • No comment pollution, dead code or hallucinated APIs.

Contract compliance

  • src/scrub-contract.json matches TOKEN_PATH_CONTRACT (scrub-contract.test.ts passes). The sibling copy in carbon-observability (agent/contracts and the Alloy scrub) must be updated next; that is the next planned PR.

Architecture violations

  • None. dist/ is committed and equals a fresh pnpm build (verified twice, by the lens review and by me).

Recommended actions

  1. Mirror the three entries in carbon-observability's contract copy and Alloy scrub (next PR). The Alloy regex must apply to the path remainder, not the whole URL.
  2. Put in the v0.1.2 release notes that /services|triggers|workflows/<a>/<b>/<c> is templated on any host.
  3. Follow-up: template token paths in log text, with the matching layer-2 change.

victor-carv and others added 2 commits October 16, 2026 18:58
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…inks and path keys

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@victor-carv
victor-carv merged commit 13dbde1 into main Oct 16, 2026
1 check passed
@victor-carv
victor-carv deleted the feat/template-slack-webhook-url branch October 16, 2026 22:06
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