Skip to content

Scrub secrets in every SDK and the ingester, and check SDK/ingester compatibility automatically - #26

Merged
sagnik11 merged 20 commits into
mainfrom
fix/tester-feedback-batch
Oct 8, 2026
Merged

sagnik11 merged 20 commits into
mainfrom
fix/tester-feedback-batch

Conversation

@sagnik11

@sagnik11 sagnik11 commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Fixes from external tester feedback. Two commits.

1. Scrub secrets before telemetry leaves the process (7d936c6)

Before: the SDKs scrubbed custom attributes but sent error messages and stack traces unscrubbed, so connect ECONNREFUSED postgres://admin:pass@… went out as-is. That data later reaches LLM prompts.

Now:

  • Node / Next SDKs. Scrub messages, stacks, captureMessage, captures made before init, errors inside withProcessSpan, and LLM-call errors and attributes. They also scrub at export time, which covers third-party spans and URLs with ?token=. The browser relay scrubs message, stack, name and nested context.
  • Browser SDK. Scrubs message, stack, event name, and context at any depth.
  • Python adapter. Gets a full redactor (adapters/python/redact.py). Before, only emails were scrubbed.
  • Ingester (defense in depth). Scrubs occurrences before fingerprinting, storage and the sink. Also scrubs span names, LLM-call rows and browser context, so older SDKs and third-party OpenTelemetry senders are covered.
  • Patterns now cover JWTs, bearer/basic auth, cookies, connection strings (including redis://:pass@ and passwords containing @), sk-proj- / Stripe / AIza / github_pat_ / GitLab keys, private keys, secret query parameters, card numbers, and sensitive key names at any depth.
  • One shared set of test cases, test-vectors/redaction.json, runs against all four implementations.
  • Secure by default. Turning it off is opt-in; customers can add their own patterns and keys.
  • Also fixes a pattern-matching slowdown already on main that could block Node for about 1 s on a 32 KB input.
  • Visible change: errors whose messages contained secrets will now group by the masked text, so some issues may regroup once (noted in CHANGELOG).

2. Automatic version compatibility check (c602bc0)

Before: users had to match SDK, ingester and platform versions by hand. A mismatch failed silently; for example, a pre-1.4.0 ingester returns 404 on /v1/logs and the SDK quietly retried.

Now:

  • One feature-to-version list: packages/otlp-ingester/src/compat-manifest.json, shared by every component.
  • Ingester:
    • adds an x-autter-ingester-version header to every response;
    • serves a public GET /v1/compat (no tenant data);
    • records which SDK and version each service uses, deduplicated to once an hour;
    • adds migration 0012-runtime-compat.
  • Node / Next SDKs. Report themselves through telemetry.distro.*. One non-blocking check per process prints a single clear warning per incompatible feature, with the fix. It never throws or delays startup, and it can be turned off with compatCheck: false or AUTTER_COMPAT_CHECK=0.
  • npx @autter/runtime-node doctor. Exits 0 when compatible, 1 on a mismatch, 2 when unreachable. Python has python3 compat.py doctor.
  • Docs. New docs/COMPATIBILITY.md, linked from the feature docs.
  • Dashboard side. The matching dashboard status is in the autter-monorepo PR.

Verification (on the combined branch)

  • npm run build: passes.
  • Test suites: runtime-node 91/91, runtime-browser 40/40, otlp-ingester 114/114.
  • Python adapter: unittest passes.
  • Browser bundle: 4.15 kB brotli, up from 3.43 kB, within the 5 kB limit.

Deploy notes

  • No version bumps are included; set the versions in the release step.
  • The dashboard's compatibility data needs this ingester deployed, because migration 0012 creates its tables.
  • Rows already in ClickHouse keep their unscrubbed data. The platform PR adds a separate scrub right before any LLM call.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


View code changes stack in Autter

Summary

Summary generated by Autter.

Why this change

Secret scrubbing was uneven across the browser, Node and Python SDKs and the ingester, so secret-shaped values could still reach stored or forwarded telemetry. There was also no automated way to tell when an SDK and the ingester are on incompatible versions.

What changes for users

Every SDK and the ingester now redact secrets and PII with shared rules and test vectors, and operators can add their own patterns. SDKs and the ingester exchange version information so incompatibilities can be detected and reported through a compat endpoint and a doctor CLI, backed by a ClickHouse record of SDK versions seen.

Implementation and review notes

  • Redaction is rewritten in runtime-core/src/redact.ts and mirrored by new redact.ts in the ingester and redact.py in the Python adapter. test-vectors/redaction.json is meant to keep them consistent, with vector tests in the Node, browser and Python suites.
  • runtime-node/src/redact-exporter.ts adds a last-line redaction wrapper around the OTLP trace exporter. A prior review noted that span links and resource attributes may pass through unscrubbed, so check that.
  • The ingester adds compat.ts, compat-manifest.json, sdk-versions.ts and a GET /v1/compat route. Every response carries an ingester-version header, and SDK sightings are recorded fire-and-forget so they never delay or fail ingest.
  • ClickHouse gains sdk_versions and ingester_info tables in schemaStatements() and a new migration in migrations.ts. Confirm the migration is idempotent and append-only, as the repo rules require.
  • config.ts adds AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS. These parse as JSON and throw a plain Error on bad input to fail startup, which a past review flagged as differing from the typed-error convention.
  • The new test-vectors/redaction.json and adapters/python/test_redact.py contain secret-shaped fixtures (JWT, Postgres URL, private key) that scanners flag. They appear to be test data, so confirm they are clearly fake.

Changes

Redaction (all surfaces)

  • packages/runtime-core/src/redact.ts is reworked (+199/-72) and is the shared rule set for the Node and browser SDKs.
  • packages/runtime-node/src/redact.ts and packages/runtime-node/src/logger.ts pick up the new options. LoggerConfig gains additional fields, and AutterServerOptions in runtime-node/src/server.ts gains redaction options. runtime-next/src/server.ts re-exports the new surface.
  • packages/runtime-node/src/redact-exporter.ts is new. It wraps the OTLP trace exporter so span and event attributes are scrubbed immediately before export. runtime-node/src/sinks.ts and runtime-core/src/otlp-logs.ts carry the new SDK version/resource fields.
  • packages/runtime-browser/src/index.ts adds in-bundle value and key scrubbing (+102/-23) and a new AutterBrowserOptions entry. The browser tracker must stay zero-dependency and under the 5 KB brotli budget, which CI checks via npm run size.
  • packages/runtime-node/src/relay.ts extends sanitizeBrowserPayload and the relay handlers with the same scrubbing, so secrets under benign context keys no longer pass through the same-origin relay.
  • packages/otlp-ingester/src/redact.ts is new and is applied via configureRedaction(config) and scrubOccurrence in server.ts. normalize-browser.ts, normalize-otlp.ts, context.ts and llm.ts now call the shared scrubText / isSensitiveKey instead of local regexes and a local scrubContext. This removes duplicated logic.
  • packages/otlp-ingester/src/config.ts adds redactValuePatterns / redactKeyPatterns, read from AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS. Invalid JSON or an invalid regex fails startup.
  • adapters/python/redact.py is new and adapters/python/caught_exceptions.py now uses it.
  • test-vectors/redaction.json is the cross-language contract. It is exercised by redact-vectors.test.mjs (browser), redact.test.mjs (node), redact.test.ts (ingester) and test_redact.py (Python).

SDK/ingester compatibility

  • packages/otlp-ingester/src/compat.ts, compat-manifest.json and sdk-versions.ts are new. They provide buildCompatReport / evaluateCompat, an SdkVersionTracker, and sdkSightingsFromOtlp.
  • packages/otlp-ingester/src/server.ts:
    • Adds a GET /v1/compat route.
    • Sets the ingester-version response header on every response.
    • Records SDK sightings via recordSdks() after successful ingest. This is fire-and-forget and never delays or fails the request.
    • Throttles reportIngesterInfo() to once per 6 hours.
  • packages/otlp-ingester/src/clickhouse.ts adds insertSdkVersions, insertIngesterInfo and schemaStatus(). schemaStatements() and migrations.ts add the sdk_versions and ingester_info tables. coded-errors.test.ts is updated for the new migration ordering.
  • packages/otlp-ingester/src/normalize-browser.ts keeps the optional sdk version field in browserPayloadSchema.
  • packages/runtime-node/src/compat.ts, doctor.ts and cli.ts are new. They add the SDK-side compat check and the doctor CLI, wired through runtime-node/package.json and tsup.config.ts. adapters/python/compat.py is the Python counterpart.
  • .github/workflows/ci.yml gets one added line, and package-lock.json gets a small update.

Docs

  • Adds docs/COMPATIBILITY.md and updates the READMEs, CHANGELOG.md, ARCHITECTURE.md, CONTINUOUS-DETECTION.md, OPERATION-LOGGING.md, MEMORY-PRESSURE.md, ENDPOINT-REGRESSIONS.md and INTEGRATIONS.md.

Breaking changes / contract notes

  • No existing wire fields change meaning. The /v1/browser v1 payload, OTLP surface and ClickHouse schema changes are additive (new tables with defaults, a new route, a new response header, an optional sdk field).
  • Stored and forwarded values are now scrubbed more aggressively. Consumers who relied on previously unmasked values, such as secret-shaped strings under benign keys, will see [redacted].
  • Invalid AUTTER_REDACT_* env values now fail ingester startup. Validate these before rolling out.
  • Message, stack and route scrubbing happens before fingerprinting. Team policy treats fingerprint changes as breaking, so confirm that scrubbed text does not regroup existing issues for common inputs.

Acceptance Criteria

  • Every vector in test-vectors/redaction.json produces the same redacted output in the Node, browser, ingester and Python implementations, and all four vector suites pass.
  • A secret-shaped value under a benign key (for example {context:{note:"sk-…"}}) sent through the browser relay and to /v1/browser is absent or redacted in the forwarded payload and in ClickHouse.
  • Span attributes and event attributes are redacted by redact-exporter.ts before export. Span links and resource attributes are scrubbed too, or the gap is explicitly documented and tracked.
  • AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS add to the built-in patterns. Malformed input fails startup with a clear message.
  • GET /v1/compat returns the ingester version, schema level and applied/pending migrations, and every ingester response includes the ingester-version header.
  • Ingesting traces, metrics or browser payloads records SDK versions in sdk_versions without adding failure modes to ingest. A ClickHouse failure there is logged and ingest still succeeds.
  • The new migration is idempotent and append-only. A fresh database (via schemaStatements()) and a migrated database end with the same sdk_versions and ingester_info shape.
  • The doctor CLI reports compatible and incompatible SDK/ingester pairings correctly (doctor.test.mjs, compat.test.mjs, test_compat.py, server.compat.test.ts).
  • npm run build passes and the browser bundle stays under the 5 KB brotli budget with zero dependencies.

Test Plan

  • Run npm run build at the repo root and confirm npm run size -w @autter/runtime-browser stays within budget.
  • Run the ingester tests (redact.test.ts, compat.test.ts, server.compat.test.ts, coded-errors.test.ts), the runtime-node tests (redact.test.mjs, compat.test.mjs, doctor.test.mjs, relay-compat.test.mjs, autoflush.test.mjs), the runtime-browser tests (redact-vectors, redact-hardening, redact-e2e) and python -m pytest adapters/python. All must pass.
  • Start the local ingester with ClickHouse from Docker Compose, then run curl -i localhost:4318/v1/compat. Check that the ingester-version header is present and that the schema level and migrations look right.
  • POST a /v1/browser payload using the documented curl request, with context containing {"note":"sk-<fake key>","debug":"AKIA<fake>"} and a fake JWT in message. Read the row back from ClickHouse and confirm no secret survives in message, stack, route or attributes.
  • Send an OTLP trace whose span attributes, event attributes, link attributes and resource attributes contain a fake secret. Confirm the stored span has none, and note whether link and resource attributes are scrubbed by redact-exporter.ts.
  • Send the same payload through the Node browser relay and confirm the forwarded body is already redacted.
  • Start the ingester with AUTTER_REDACT_VALUE_PATTERNS='["internal-[0-9]{6}"]' and confirm a matching value is masked. Then set AUTTER_REDACT_VALUE_PATTERNS='not json' and confirm startup fails with a clear error.
  • Run the doctor CLI against the local ingester using a current SDK version, then against an out-of-range version. Check that the output and exit code match docs/COMPATIBILITY.md.
  • After a few ingests, query sdk_versions and ingester_info in ClickHouse. Confirm the SDK rows are present and that reportIngesterInfo writes at most once per throttle window.
  • Restart the ingester against an already-migrated database to confirm the new migration re-runs without error. Also boot against a fresh database and compare the table shapes.
  • Check that a fixture error produces the same fingerprint before and after scrubbing for ordinary messages, to rule out unintended issue regrouping.

Rollback Plan

  • Revert the PR on main and redeploy the previous ingester image. For single-server, re-run the deploy so only the ingester is recreated. For ECS, register the prior task definition revision and roll the service.
  • Publish or pin the previous versions of @autter/runtime-node, @autter/runtime-browser, @autter/runtime-next and the Python adapter. Package versions are independent.
  • If the failure is only the new redaction patterns, unset AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS and restart.
  • No ClickHouse rollback is needed. The sdk_versions and ingester_info tables are additive, and the migration is recorded in schema_migrations. Leave them in place, and do not edit or delete the shipped migration. If cleanup is wanted, drop the two tables manually and append a corrective migration.
  • After rollback, confirm that ingest succeeds with the older image and that /v1/browser and OTLP requests still write rows. Also confirm that GET /v1/compat is no longer served, if the revert covers it.

Related Issues

No linked issue was identified from the branch name (fix/tester-feedback-batch), the PR title or the supplied diff context.

Written for commit 0f05407. Summary will update on new commits.

sagnik11 and others added 6 commits October 7, 2026 23:49
Exception data is what reaches LLM-generated fixes, and it routinely
carries secrets: `connect ECONNREFUSED postgres://admin:hunter2@…`,
provider errors echoing API keys, `?token=` in request URLs, cookies and
bearer tokens in serialized headers. Redaction previously covered only
custom attributes (and only top-level, email-only, in the browser), so
messages, stack traces, span status messages, third-party spans, relayed
browser events and anything an old SDK or plain OTel sender shipped went
to storage and the sink verbatim.

SDKs (scrub before anything leaves the customer's process, on by default):
- runtime-node: scrub exception messages/stacks/status messages in
  captureException/captureMessage (incl. pre-init fallbacks), process
  spans, withLlmCall/trackLlmCall errors, LlmCallHandle.setAttributes and
  instrumentLlmClient; add a RedactingSpanExporter so every exported span
  (HTTP URLs, headersToSpanAttributes, third-party instrumentations,
  app-level recordException) is scrubbed; relay scrubs browser
  message/stack/name/nested context (new `redact` option); new redactText
- runtime-browser: scrub messages, stacks, names and nested context; new
  `redact: { keys, values } | false` option and scrubText export
  (3.43 kB -> 4.14 kB brotlied, budget 5 kB)
- python adapter: new stdlib-only redact.py; caught-exception sampler
  scrubs tracebacks with it

Patterns: add Basic auth, Authorization/Cookie/Set-Cookie header text,
connection strings with empty user or `@` in the password, sk-proj/
sk-ant, Stripe, GitHub fine-grained, GitLab, npm, SendGrid, Google keys,
password=/?token=/?api_key= assignments, Luhn-valid cards; keys for any
*authorization header, session/sessionid/sid, pwd, dsn, bounded ssn.
Custom value patterns now apply globally. Email and URL-scheme
quantifiers are bounded (email was quadratic on long strings: ~1 s per
32 KB, now ~10 ms).

Ingester (second line of defence for old SDKs / third-party OTLP senders,
before ClickHouse and the sink that feeds LLM fixing): scrub occurrence
message/stack/route/errorType, span names, deep browser context and
LLM-call attributes with the shared patterns; extra patterns via
AUTTER_REDACT_VALUE_PATTERNS / AUTTER_REDACT_KEY_PATTERNS.

Parity: test-vectors/redaction.json runs against node, browser, ingester
and Python; CI now runs the Python adapter tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…omotion

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ime-edge

Adds the private runtime-core package (coded errors, record building, OTLP
logs encoding, redaction) bundled into runtime-node 1.5.0 and the new
@autter/runtime-edge 1.0.0. runtime-node gains request summaries
(autterRequests, autterFastify, withRuntimeRequest), runtimeContext,
inline messages, RuntimeError/defineRuntimeErrors/autterErrorResponse,
fork/carrier, AI rollup, waitUntil, enrichers, sinks, a /testing subpath
and initAutterLogging. 1.4.0 output is golden-tested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Redaction regexes are linear on adversarial strings: email, URL
  credential, JWT, Slack and Autter-key patterns only start a match at the
  beginning of a run, query stripping is procedural, and strings are capped
  before scrubbing (runtime-core, ingester, browser).
- runtime-edge queues each record with its own destination and drops
  records when no key is configured.
- /v1/logs promotion lookups are bounded in span, count and time range,
  newest first, with a per-tenant PROMOTION_LOOKUPS_PER_MINUTE budget.
- runtime-browser reads optional error metadata defensively.
- The sink keeps statusCode 0; proxy-addr 2.0.8 (CVE-2026-90711).
- Test scripts build the workspace packages they import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Users had to match SDK, ingester and ClickHouse schema versions by hand,
and a mismatch failed silently. For example, operation logging (1.4.0)
sent to an older ingester got 404s that the SDK retried quietly. Runtime
now checks this itself.

- One source of truth: packages/otlp-ingester/src/compat-manifest.json
  lists each feature's minimum ingester, migrations, route and minimum SDK
  versions. compat.ts holds the shared, dependency-free evaluation, which
  the Node SDK bundles at build time.
- Ingester: GET /v1/compat (public, no tenant data) returns the version,
  schema state and level, and per-feature availability, plus evaluated
  issues for ?features=&sdk=. Every response carries
  x-autter-ingester-version (CORS-exposed on /v1/browser). Migration
  0012-runtime-compat records the SDK name and version per service in
  runtime_sdk_versions (deduplicated hourly, fire-and-forget) and the
  ingester's own version in runtime_ingester_info.
- runtime-node / runtime-next: report themselves as telemetry.distro.*.
  When a feature that needs a newer ingester is in use, check once in the
  background and warn once per feature, naming both versions and the fix.
  The check never throws and never delays startup or exit (unref'd socket).
  It respects compatCheck: false, AUTTER_COMPAT_CHECK=0 and debug mode.
  Pre-compat ingesters are detected by a 404 on the feature's route. The
  browser relay checks CSP and network events against the ingester's
  version header.
- npx @autter/runtime-node doctor: a one-shot report. Exit 0 compatible,
  1 mismatch or rejected key, 2 unreachable.
- runtime-browser sends its version as `sdk` (+10 bytes, 4.15 kB brotli).
- Python adapter: stdlib compat.py with warn_if_incompatible and a
  `doctor` command, and a parity test against the manifest.
- docs/COMPATIBILITY.md plus pointers from the docs that described manual
  version matching.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@autter-dev

autter-dev Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

🚦 Pre-merge checks · ⚠️ 11 warning, ✅ 197 passed

Needs attention

Check Status Explanation
Too many files changed ⚠️ Warning This PR changes 70 files (limit 50). Consider splitting this PR by area: packages (53 files), docs (7 files), adapters (5 files), (root) (3 files), test-vectors (1 file), .github (1 file).
Too many lines changed ⚠️ Warning This PR changes 5501 lines (limit 1000). Splitting into smaller, focused PRs makes review more reliable.
PII stored without application-level encryption ⚠️ Warning 3 potential issue(s) detected (max risk 91/100): CHANGELOG.md:26, packages/otlp-ingester/README.md:85, test-vectors/redaction.json:107.
Missing security-team review on sensitive path ⚠️ Warning 1 root-cause issue(s) detected (max risk 80/100): packages/otlp-ingester/src/server.ts:71.
Missing input validation ⚠️ Warning 1 potential issue(s) detected (max risk 94/100): packages/otlp-ingester/src/server.ts:195.
API key in source ⚠️ Warning 1 potential secret(s) detected (max risk 98/100): packages/runtime-node/test/fixtures/e2e-redaction.mjs:50.
Private key in source ⚠️ Warning 13 root-cause issue(s) detected (max risk 100/100): adapters/python/test_redact.py:52, test-vectors/redaction.json:6, test-vectors/redaction.json:51, test-vectors/redaction.json:61, test-vectors/redaction.json:103.
Runtime error risk ⚠️ Warning 1 potential issue(s) detected (max risk 33/100): adapters/python/redact.py:181.
Maintainability issue ⚠️ Warning 3 potential issue(s) detected (max risk 49/100): adapters/python/compat.py:309, adapters/python/compat.py:360, adapters/python/test_compat.py:21.
Co-change coupling ⚠️ Warning 2 file(s) changed without a partner they usually change with.
Release Notes Curator ⚠️ Warning 1 root-cause issue(s) detected (max risk 40/100): packages/otlp-ingester/src/server.ts:114.
✅ Passed checks (197)
Check Status Explanation
Too many unrelated chapters ✅ Passed 6 chapter(s) detected, within the limit of 6.
Generated files hiding real changes ✅ Passed Generated-file volume (3 lines) does not obscure the 5498 hand-written line(s).
Missing PR context ✅ Passed PR context looks sufficient.
Mixed concerns (refactor + behavior change) ✅ Passed The PR bundles two separate features, secret redaction and the compat check. Each is a behavior change. The consolidation in normalize-browser.ts, context.ts and llm.ts, which swaps local regexes for the shared scrubText, is part of the redaction behavior change and not a standalone refactor. There is no pure rename or ... [truncated 37 chars]
Migration + app logic + UI combined in one PR ✅ Passed The PR adds a ClickHouse migration (0012-runtime-compat in migrations.ts and clickhouse.ts) together with ingester and SDK logic. It contains no user-interface changes. The dashboard UI is in a separate autter-monorepo PR, and the browser SDK is telemetry code, not UI.
Sensitive data in logs ✅ Passed No sensitive data in logs issues detected.
Log injection ✅ Passed No log injection issues detected.
Missing audit logging ✅ Passed No missing audit logging issues detected.
Removed observability ✅ Passed No removed observability issues remaining after verification.
Silent exception swallowing ✅ Passed No silent exception swallowing issues remaining after verification.
Circuit breaker not detected ✅ Passed No circuit breaker not detected issues remaining after verification.
Stack trace leakage ✅ Passed No stack trace leakage issues detected.
Multi-write without detected transaction ✅ Passed No multi-write without detected transaction issues remaining after verification.
Possible TOCTOU in critical path ✅ Passed No possible toctou in critical path issues remaining after verification.
Idempotency key not detected ✅ Passed No idempotency key not detected issues remaining after verification.
Possible non-atomic read-modify-write ✅ Passed No possible non-atomic read-modify-write issues remaining after verification.
Optimistic locking not detected ✅ Passed No optimistic locking not detected issues remaining after verification.
Rate limiting not detected ✅ Passed No rate limiting not detected issues remaining after verification.
Rate limiting removed ✅ Passed No rate limiting removed issues detected.
Batch size limit not detected ✅ Passed No batch size limit not detected issues remaining after verification.
Pagination not detected ✅ Passed No pagination not detected issues detected.
Prompt injection risk ✅ Passed No LLM/AI-integration code touched by this diff.
LLM output used in a dangerous sink ✅ Passed No LLM/AI-integration code touched by this diff.
Sensitive data in prompt or system-prompt leakage ✅ Passed No LLM/AI-integration code touched by this diff.
Over-privileged LLM tool / excessive agency ✅ Passed No LLM/AI-integration code touched by this diff.
Missing validation on an LLM-driven decision ✅ Passed No LLM/AI-integration code touched by this diff.
Unbounded LLM usage (denial-of-wallet) ✅ Passed No LLM/AI-integration code touched by this diff.
Table exposed without row-level security ✅ Passed No row-level-security-related code touched by this diff.
Over-broad row-level security policy ✅ Passed No row-level-security-related code touched by this diff.
Code path that bypasses row-level security ✅ Passed No row-level-security-related code touched by this diff.
Privileged database credential reachable from the client ✅ Passed No row-level-security-related code touched by this diff.
Privileged query without row-level scoping ✅ Passed No row-level-security-related code touched by this diff.
Row-level security enabled with no policy ✅ Passed No row-level-security-related code touched by this diff.
Template-default gradient styling ✅ Passed No added frontend pages or design-slop markers in this diff.
Interchangeable AI marketing copy ✅ Passed No added frontend pages or design-slop markers in this diff.
Placeholder content shipped to users ✅ Passed No added frontend pages or design-slop markers in this diff.
Emoji standing in for an icon system ✅ Passed No added frontend pages or design-slop markers in this diff.
Call-to-action that goes nowhere ✅ Passed No added frontend pages or design-slop markers in this diff.
Templated page composition ✅ Passed No added frontend pages or design-slop markers in this diff.
Color outside the brand palette ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Hardcoded style bypassing design tokens ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Typography outside the brand type system ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
One-off UI instead of the shared component ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Copy that does not match brand voice ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Screen does not match the rest of the product ✅ Passed No added frontend markup or brand-relevant style changes in this diff.
Merge-blocking marker left in the change ✅ Passed No pending-work markers added by this diff.
Known-defect marker shipped in code ✅ Passed No pending-work markers added by this diff.
Untracked TODO without an issue reference ✅ Passed No pending-work markers added by this diff.
Test disabled or left pending ✅ Passed No pending-work markers added by this diff.
PII in logs ✅ Passed No pii in logs issues detected.
PII or internals leaked in error response ✅ Passed No pii or internals leaked in error response issues detected.
User data stored without retention controls ✅ Passed No user data stored without retention controls issues detected.
PII sent to external / cross-border destination ✅ Passed No pii sent to external / cross-border destination issues detected.
Lockfile resolution / integrity tampered ✅ Passed No lockfile resolution / integrity tampered issues detected.
Dependency runs install-time lifecycle script ✅ Passed No dependency runs install-time lifecycle script issues detected.
Possible dependency-confusion attack ✅ Passed No possible dependency-confusion attack issues detected.
Lockfile resolves a dependency the manifest does not declare ✅ Passed No lockfile resolves a dependency the manifest does not declare issues detected.
Checked-in build artefact modified without source change ✅ Passed No checked-in build artefact modified without source change issues detected.
Dockerfile build-step is insecure ✅ Passed No dockerfile build-step is insecure issues detected.
External artefact pulled in without integrity pinning ✅ Passed No external artefact pulled in without integrity pinning issues detected.
Changed export, importer not updated ✅ Passed No changed export with an un-updated importer detected.
Source changes without matching tests ✅ Passed No source changes without matching tests issues detected.
Migration missing rollback / down step ✅ Passed No migration missing rollback / down step issues remaining after verification.
Frontend importing database client directly ✅ Passed No frontend importing database client directly issues detected.
Route handler bypassing service layer ✅ Passed No route handler bypassing service layer issues detected.
Backend service importing UI module ✅ Passed No backend service importing ui module issues detected.
Cross-context internals import ✅ Passed No cross-context internals import issues detected.
Workspace package rule violation ✅ Passed No workspace package rule violation issues detected.
Inconsistent logging pattern ✅ Passed No inconsistent logging pattern issues detected.
Inconsistent error handling ✅ Passed No inconsistent error handling issues remaining after verification.
Endpoint missing input validation ✅ Passed No endpoint missing input validation issues detected.
Multi-write without transaction wrapper ✅ Passed No multi-write without transaction wrapper issues remaining after verification.
New feature shipped without feature flag ✅ Passed No new feature shipped without feature flag issues detected.
Module placed in the wrong workspace package ✅ Passed No module placed in the wrong workspace package issues detected.
Hallucinated import (package not installed) ✅ Passed No hallucinated import (package not installed) issues remaining after verification.
Nonexistent package (not found in registry) ✅ Passed No nonexistent package (not found in registry) issues detected.
Call to function that does not exist ✅ Passed No call to function that does not exist issues detected.
Generic placeholder identifier in production logic ✅ Passed No generic placeholder identifier in production logic issues remaining after verification.
Repetitive boilerplate (duplicated block) ✅ Passed No repetitive boilerplate (duplicated block) issues detected.
Overbroad try/catch swallowing all exceptions ✅ Passed No overbroad try/catch swallowing all exceptions issues detected.
TODO / FIXME on critical path ✅ Passed No todo / fixme on critical path issues detected.
Comment contradicts or fabricates code behaviour ✅ Passed No comment contradicts or fabricates code behaviour issues detected.
Abstraction defined but never used ✅ Passed No abstraction defined but never used issues detected.
Code style differs from rest of codebase ✅ Passed No code style differs from rest of codebase issues detected.
Established pattern ignored ✅ Passed No established pattern ignored issues detected.
Unhandled edge case (null / empty / zero / boundary) ✅ Passed No unhandled edge case (null / empty / zero / boundary) issues detected.
Insecure training-data / doc-example pattern ✅ Passed No insecure training-data / doc-example pattern issues remaining after verification.
Dead code (defined but never referenced) ✅ Passed No dead code (defined but never referenced) issues detected.
Deprecated API call ✅ Passed No deprecated api call issues detected.
API pattern from wrong library version ✅ Passed No api pattern from wrong library version issues detected.
API endpoint removed ✅ Passed No api endpoint removed issues detected.
HTTP method changed (GET ↔ POST etc.) ✅ Passed No http method changed (get ↔ post etc.) issues detected.
New required field added to request ✅ Passed No new required field added to request issues remaining after verification.
Field removed from response schema ✅ Passed No field removed from response schema issues detected.
Response field type changed ✅ Passed No response field type changed issues detected.
HTTP status code changed ✅ Passed No http status code changed issues detected.
Auth requirement added / removed / changed ✅ Passed No auth requirement added / removed / changed issues detected.
Error response shape changed ✅ Passed No error response shape changed issues detected.
Pagination behaviour changed ✅ Passed No pagination behaviour changed issues detected.
Outbound webhook payload schema changed ✅ Passed No outbound webhook payload schema changed issues detected.
GraphQL field removed without deprecation ✅ Passed No graphql field removed without deprecation issues detected.
GraphQL enum value removed ✅ Passed No graphql enum value removed issues detected.
Vendor API consumer ✅ Passed This PR does not touch call sites of an open vendor API change.
SQL injection ✅ Passed No sql injection issues detected.
Cross-site scripting (XSS) ✅ Passed No cross-site scripting (xss) issues detected.
Path traversal ✅ Passed No path traversal issues detected.
Command injection ✅ Passed No command injection issues detected.
Insecure deserialization ✅ Passed No insecure deserialization issues detected.
Weak cryptography ✅ Passed No weak cryptography issues detected.
Insecure randomness for security material ✅ Passed No insecure randomness for security material issues detected.
Unsafe file upload ✅ Passed No unsafe file upload issues detected.
Unsafe CORS configuration ✅ Passed No unsafe cors configuration issues detected.
Unsafe / open redirect ✅ Passed No unsafe / open redirect issues detected.
Missing CSRF protection ✅ Passed No missing csrf protection issues detected.
Unsafe cookie / session settings ✅ Passed No unsafe cookie / session settings issues detected.
Sensitive data exposure ✅ Passed No sensitive data exposure issues detected.
Invisible Unicode / Trojan Source characters ✅ Passed No invisible unicode / trojan source characters issues detected.
Access token in source ✅ Passed No access token in source detected.
Cloud credential in source ✅ Passed No cloud credential in source detected.
Webhook signing secret in source ✅ Passed No webhook signing secret in source detected.
OAuth client secret in source ✅ Passed No oauth client secret in source detected.
JWT signing secret in source ✅ Passed No jwt signing secret in source detected.
Hardcoded password ✅ Passed No hardcoded password detected.
Dependency has known CVE ✅ Passed No dependency has known cve findings.
Malware package in dependency ✅ Passed No malware package in dependency findings.
Possible typosquat dependency ✅ Passed No possible typosquat dependency findings.
Newly introduced dependency ✅ Passed No newly introduced dependency issues remaining after verification.
Unpinned production dependency ✅ Passed No unpinned production dependency findings.
Deprecated dependency ✅ Passed No deprecated dependency findings.
License allow-list violation ✅ Passed No license allow-list violation findings.
Low dependency grade ✅ Passed No low dependency grade findings.
pull_request_target executes untrusted PR code ✅ Passed No pull_request_target executes untrusted pr code issues detected.
Repository secrets exposed to fork PRs ✅ Passed No repository secrets exposed to fork prs issues detected.
Overbroad GITHUB_TOKEN / pipeline permissions ✅ Passed No overbroad github_token / pipeline permissions issues detected.
Third-party action pinned by mutable tag ✅ Passed No third-party action pinned by mutable tag issues detected.
Shell injection via workflow expression ✅ Passed No shell injection via workflow expression issues detected.
Cache poisoning risk from fork PRs ✅ Passed No cache poisoning risk from fork prs issues detected.
Deployment workflow changed ✅ Passed No deployment workflow changed issues detected.
Environment protection rule weakened ✅ Passed No environment protection rule weakened issues detected.
Auth middleware removed from route ✅ Passed No auth middleware removed from route issues detected.
Route protection changed (protected → public) ✅ Passed No route protection changed (protected → public) issues detected.
Permission / RBAC check removed ✅ Passed No permission / rbac check removed issues detected.
Required role weakened ✅ Passed No required role weakened issues detected.
Admin-only route exposed to lower privilege ✅ Passed No admin-only route exposed to lower privilege issues detected.
Token validation skipped in middleware chain ✅ Passed No token validation skipped in middleware chain issues detected.
JWT verification weakened or changed ✅ Passed No jwt verification weakened or changed issues detected.
Session expiration / TTL changed ✅ Passed No session expiration / ttl changed issues detected.
Password reset flow changed ✅ Passed No password reset flow changed issues detected.
OAuth callback / redirect handling changed ✅ Passed No oauth callback / redirect handling changed issues detected.
Webhook endpoint missing signature verification ✅ Passed No webhook endpoint missing signature verification issues detected.
Public route touches private/PII data ✅ Passed No public route touches private/pii data issues detected.
Table dropped (data loss) ✅ Passed No table dropped (data loss) issues detected.
Column dropped (data loss) ✅ Passed No column dropped (data loss) issues detected.
Column type narrowed (truncation risk) ✅ Passed No column type narrowed (truncation risk) issues detected.
Constraint removed ✅ Passed No constraint removed issues detected.
Index dropped ✅ Passed No index dropped issues detected.
NULL → NOT NULL (backfill required) ✅ Passed No null → not null (backfill required) issues detected.
NOT NULL → NULL (constraint relaxed) ✅ Passed No not null → null (constraint relaxed) issues detected.
Column default changed ✅ Passed No column default changed issues detected.
Primary key changed (FK cascade risk) ✅ Passed No primary key changed (fk cascade risk) issues detected.
Foreign key changed ✅ Passed No foreign key changed issues detected.
Unique constraint removed (duplicate risk) ✅ Passed No unique constraint removed (duplicate risk) issues detected.
Enum value removed ✅ Passed No enum value removed issues detected.
Column renamed without compatibility alias ✅ Passed No column renamed without compatibility alias issues detected.
Table renamed without compatibility view ✅ Passed No table renamed without compatibility view issues detected.
Long-locking migration operation ✅ Passed No long-locking migration operation issues detected.
CREATE INDEX without CONCURRENTLY ✅ Passed No create index without concurrently issues detected.
CONCURRENTLY inside a transaction ✅ Passed No concurrently inside a transaction issues detected.
New enum value used in the same transaction ✅ Passed No new enum value used in the same transaction issues detected.
Foreign key added without NOT VALID ✅ Passed No foreign key added without not valid issues detected.
Foreign key column is not indexed ✅ Passed No foreign key column is not indexed issues detected.
Table created without a primary key ✅ Passed No table created without a primary key issues detected.
Timestamp without time zone ✅ Passed No timestamp without time zone issues detected.
Money stored as a float ✅ Passed No money stored as a float issues detected.
Volatile default rewrites the table ✅ Passed No volatile default rewrites the table issues detected.
CHECK constraint added without NOT VALID ✅ Passed No check constraint added without not valid issues detected.
Row-level security policy column is not indexed ✅ Passed No row-level security policy column is not indexed issues detected.
UNIQUE column still allows many NULLs ✅ Passed No unique column still allows many nulls issues detected.
CONCURRENTLY index is not retry-safe ✅ Passed No concurrently index is not retry-safe issues detected.
Frontend performance issue ✅ Passed No additional explanation was reported.
Frontend security issue ✅ Passed No additional explanation was reported.
Frontend correctness issue ✅ Passed No additional explanation was reported.
Accessibility issue ✅ Passed No additional explanation was reported.
Frontend maintainability issue ✅ Passed No additional explanation was reported.
Code correctness issue ✅ Passed No code correctness issue issues remaining after verification.
Resource leak risk ✅ Passed No additional explanation was reported.
Data integrity risk ✅ Passed No additional explanation was reported.
Redundant alias / duplicate import ✅ Passed No additional explanation was reported.
Redundant type construct ✅ Passed No additional explanation was reported.
Unnecessary type assertion ✅ Passed No additional explanation was reported.
Module smell ✅ Passed No additional explanation was reported.
Dead export (no callers) ✅ Passed No additional explanation was reported.
Code duplication / DRY violation ✅ Passed No additional explanation was reported.
AI authorship ✅ Passed 60.3% AI-authored (claude:claude-opus-5-5: 60%), 0% human, 40% untracked. (partial coverage — some commits not tracked)
Intent vs. implementation ✅ Passed The reviewed part of the diff delivers the ingester-side scrubbing and the compatibility tracking the PR describes; the Node, Next, browser and Python SDK work sits in omitted files and could not be checked. Requirements: 2 implemented, 3 partial. 1 change(s) with no backing requirement. (Intent from product context, P ... [truncated 15 chars]
Complexity Guard ✅ Passed No additional explanation was reported.
Bundle Size Monitor ✅ Passed No additional explanation was reported.

This comment is updated automatically whenever Autter reviews a new PR revision.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 10 finding(s) as review threads below (🔴 6 · 🟠 4). Each carries a copy-paste AI fix prompt.

async insertSdkVersions(ctx: IngestContext, rows: SdkVersionRow[]): Promise<void> {
if (!rows.length || !this.configured) return;
await this.ensureSchema();
await this.getClient().insert({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Multi-write without transaction wrapper — Risk: 100/100

Multiple writes (2) in the same change without a transaction wrapper. Blast radius — violating this convention cascades to the downstream usage that depends on this file: functions ClickHouseStore, sanitizeBrowserPayload, extractLlmCall, normalizeTraces, createBrowserRelayFetchHandler, instrumentLlmClient, createBrowserRelayHandler, loadConfig; endpoints POST ${feature.route}, GET /v1/compat; scopes @autter/otlp-ingester; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Functions/symbols: ClickHouseStore, sanitizeBrowserPayload, extractLlmCall, normalizeTraces, createBrowserRelayFetchHandler, instrumentLlmClient, createBrowserRelayHandler, loadConfig
  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
  • Scopes: @autter/otlp-ingester
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/otlp-ingester/src/clickhouse.ts` around line 250, multiple writes happen in the same hunk without a surrounding transaction (no `transaction(`/`db.tx(`/`withTransaction`/`@transactional`/`with session.begin()`/`BEGIN ... COMMIT`). Wrap them in a transaction so a partial failure cannot leave data inconsistent (e.g. money debited but order not created). Blast radius — violating this convention cascades to the downstream usage that depends on this file: functions `ClickHouseStore`, `sanitizeBrowserPayload`, `extractLlmCall`, `normalizeTraces`, `createBrowserRelayFetchHandler`, `instrumentLlmClient`, `createBrowserRelayHandler`, `loadConfig`; endpoints `POST ${feature.route}`, `GET /v1/compat`; scopes `@autter/otlp-ingester`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`.

Flagged by Autter security & observability checks.

{
"name": "PEM private key block",
"skip": ["browser"],
"input": "cfg -----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAabc\n-----END RSA PRIVATE KEY----- loaded",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 [deterministic] Private key in source — Risk: 100/100

A private key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `test-vectors/redaction.json` around line 103 a private key is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Generate a new keypair, distribute the new public key to consumers, and delete the leaked private key. Anything signed by the old key should be re-issued. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.

def test_nested_values_and_usage_counters(self):
out = redact_attributes(
{
"db": {"dsn": "postgres://u:p@h/db", "args": ["redis://:pw@cache:6379"]},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 [deterministic] Database connection URL with embedded credentials — Risk: 96/100

A Postgres connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `adapters/python/test_redact.py` around line 52 a Postgres connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.

},
{
"name": "mysql URL whose password contains @",
"input": "mysql://root:p@ss@db:3306/shop",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 [deterministic] Database connection URL with embedded credentials — Risk: 96/100

A MySQL connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `test-vectors/redaction.json` around line 61 a MySQL connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.

...(opts.release ? { release: opts.release } : {}),
// SDK version: the ingester records it so version mismatches are
// visible (and checked server-side by the relay). Ignored by older ingesters.
sdk: SDK_VERSION,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 New required field added to request — Risk: 94/100

New required field appears here (TS/JS field). Existing callers that omit it will fail validation. Blast radius — if this contract change ships, the following consumers break: functions AutterBrowserOptions, BrowserEvent, sanitizeBrowserPayload, extractLlmCall, normalizeTraces, createBrowserRelayFetchHandler, instrumentLlmClient, createBrowserRelayHandler; endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Functions/symbols: AutterBrowserOptions, BrowserEvent, sanitizeBrowserPayload, extractLlmCall, normalizeTraces, createBrowserRelayFetchHandler, instrumentLlmClient, createBrowserRelayHandler
  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-browser/src/index.ts` around line 428, this PR adds a new REQUIRED field to a request body / params. Every existing caller that omits it will start failing validation. Either give the field a sensible default, mark it optional, or bump the API version so old clients keep working. Blast radius — if this contract change ships, the following consumers break: functions `AutterBrowserOptions`, `BrowserEvent`, `sanitizeBrowserPayload`, `extractLlmCall`, `normalizeTraces`, `createBrowserRelayFetchHandler`, `instrumentLlmClient`, `createBrowserRelayHandler`; endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`.

Flagged by Autter security & observability checks.

"text": [
{
"name": "JWT inside an error message",
"input": "invalid session eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c for user",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 [deterministic] Hardcoded secret — Risk: 94/100

A JWT-shaped value appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `test-vectors/redaction.json` around line 6, what looks like a real credential is committed in source. Move it to a secret manager / env var, rotate the leaked value, and add the pattern to `.gitleaks`/`detect-secrets` so it cannot land again. If this is genuinely test data, prefix the value with `EXAMPLE_` / `YOUR_KEY` or mock the credential. Blast radius — if this is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`.

Flagged by Autter security & observability checks.

request: { headers: { authorization: "Bearer abcdefghijklmnop123" }, url: "/cb?access_token=tok123456" },
});
captureMessage("payment for ORD-12345 used token eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.SflKxwRJSMeKKF2QT4fwpM");
listeners.get("unhandledrejection")({ reason: new Error("redis://:cachepw@cache:6379 down") });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Database connection URL with embedded credentials — Risk: 69/100

A Redis connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-browser/test/redact-e2e.test.mjs` around line 35 a Redis connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.

// A process span whose thrown error carries a secret.
await autter
.withProcessSpan("nightly-sync", () => {
throw new Error("redis://:redispass99@cache:6379 refused");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Database connection URL with embedded credentials — Risk: 69/100

A Redis connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/test/fixtures/e2e-redaction.mjs` around line 42 a Redis connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.

await autter
.withLlmCall({ provider: "openai", model: "gpt-x" }, (llm) => {
llm.setAttributes({ "gen_ai.request.api_key": "should-not-leak", note: "ok" });
throw new Error("401 Incorrect API key provided: sk-proj-abcdefghijklmnopqrstuvwxyz0123");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] API key in source — Risk: 69/100

A generic api key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/test/fixtures/e2e-redaction.mjs` around line 50 a generic api key is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Revoke the leaked token on the provider console, mint a replacement scoped to the minimum permissions you need, and audit recent provider-side activity. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.


test("secrets inside nested string values are scrubbed, not just keys", () => {
const out = redactAttributes({
job: { args: ["--db", "postgres://u:pw123@db/x"], note: "Cookie: a=b" },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Database connection URL with embedded credentials — Risk: 69/100

A Postgres connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints POST ${feature.route}, GET /v1/compat; dependent files packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts.

References:

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • API endpoints: POST ${feature.route}, GET /v1/compat
  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/index.ts, packages/otlp-ingester/src/auth.ts, packages/otlp-ingester/src/sink.ts, packages/otlp-ingester/src/normalize-browser.test.ts, packages/otlp-ingester/src/normalize.test.ts, packages/otlp-ingester/src/sink.test.ts, packages/otlp-ingester/src/server.sink.test.ts
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/test/redact.test.mjs` around line 318 a Postgres connection URL with credentials is hard-coded in source. Treat the literal as compromised even if the PR is closed without merging. Replace the embedded password with an env-var reference (`postgres://app:${PG_PASSWORD}@host/db`) and rotate the database user password on the database server. Move the value to your project's secret manager (AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / HashiCorp Vault / Doppler / 1Password) and load it at runtime via an env var. Diff-only: rotation + amending this PR (drop the literal) is sufficient. Affected services / downstream impact Blast radius — if this credential is exploited it cascades to the downstream usage that depends on this file: endpoints `POST ${feature.route}`, `GET /v1/compat`; dependent files `packages/otlp-ingester/src/normalize-otlp.ts`, `packages/otlp-ingester/src/index.ts`, `packages/otlp-ingester/src/auth.ts`, `packages/otlp-ingester/src/sink.ts`, `packages/otlp-ingester/src/normalize-browser.test.ts`, `packages/otlp-ingester/src/normalize.test.ts`, `packages/otlp-ingester/src/sink.test.ts`, `packages/otlp-ingester/src/server.sink.test.ts`..

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

🧭 PR hygiene & process suggestions

Autter has 3 suggestion(s) about the shape of this PR (size, scope, reviewability). These are process guidance — not code defects — so they are consolidated here instead of posted as inline comments on individual files.

🟡 Requirement only partially built — Risk: 38/100

Flagged in 3 places: .github/workflows/ci.yml:25, packages/otlp-ingester/src/config.ts:1, packages/otlp-ingester/src/normalize-browser.ts:84.

The PR description asked for: "Python adapter gets a full redactor", but the diff only partially delivers it. CI now runs the Python adapter tests, and the PR lists redact.py and test_redact.py. Those files are in the omitted set, so their content was not checked.

🛠 AI fix prompt (copy & paste into your coding agent)
Implement "Python adapter gets a full redactor" as the PR description asked, or confirm it is intentionally deferred and record that in the PR description.

Flagged by Autter PR-hygiene checks.


⚠️ 2 unconfirmed finding(s) — flagged by a detector but not proven by Autter's verification pass

Inline comments are reserved for findings that survived verification. These are plausible but could not be confirmed from the available context, so they are listed here as FYIs instead — review the ones that look real to you.

  • 🟡 Handle SDK version tracking failures (risk 40/100) — packages/otlp-ingester/src/server.ts:114 — reportIngesterInfo wraps all of its awaits in try/catch, so void reportIngesterInfo() cannot reject. Whether void sdkVersions.observe(...) can produce an unhandled rejection depends on SdkVersionTracker.observe in sdk-versions.ts, which was not provided. It may catch insert failures internally, since the comment says 'never delays or fails it'. The synchronous sdkSightingsFromOtlp call
  • 🟡 Missing security-team review on sensitive path (risk 30/100) — packages/otlp-ingester/src/server.ts:71 — This is a process/policy finding about review approval state, not a code defect. The provided code cannot show whether a security-team review exists or is required.

🔎 26 low-signal finding(s) (test-file conventions, hardening advice on internal routes, packages the registry knows) were kept off this PR — see the Autter dashboard.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 8 finding(s) as review threads below (🟠 8). Each carries a copy-paste AI fix prompt.

for (const feature of COMPAT_MANIFEST.features) {
assert.ok(!ids.has(feature.id), `duplicate ${feature.id}`);
ids.add(feature.id);
assert.ok(compareVersions(feature.ingester, pkgVersion("otlp-ingester"))! <= 0, `${feature.id}: ingester ${feature.ingester} is unreleased`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/noNonNullAssertion — Risk: 55/100

Forbidden non-null assertion.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/noNonNullAssertion` issue at packages/otlp-ingester/src/compat.test.ts:36: Forbidden non-null assertion.

Flagged by Autter security & observability checks.

const right = parseVersion(b);
if (!left || !right) return null;
for (let i = 0; i < 4; i++) {
if (left[i]! !== right[i]!) return left[i]! < right[i]! ? -1 : 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/noNonNullAssertion — Risk: 55/100

Forbidden non-null assertion.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/noNonNullAssertion` issue at packages/otlp-ingester/src/compat.ts:82: Forbidden non-null assertion.

Flagged by Autter security & observability checks.

const missing = feature.migrations.filter((m) => !applied.has(m));
if (schema.status === "failed" || (schema.status === "ready" && missing.length)) {
const schemaFix =
"Check the ingester's CLICKHOUSE_URL/credentials and its logs, then restart it so the boot migrations run. " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/useTemplate — Risk: 55/100

Template literals are preferred over string concatenation.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useTemplate` issue at packages/otlp-ingester/src/compat.ts:239: Template literals are preferred over string concatenation.

Flagged by Autter security & observability checks.

occurredAt: Date,
counts: { requestCount?: number; errorCount?: number; sessionCount?: number },
): void {
route = scrubText(route);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/noParameterAssign — Risk: 55/100

Reassigning a function parameter is confusing.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/noParameterAssign` issue at packages/otlp-ingester/src/normalize-browser.ts:113: Reassigning a function parameter is confusing.

Flagged by Autter security & observability checks.


test("sensitive keys are masked at any depth; safe keys survive", () => {
for (const key of vectors.keys.sensitive) {
const out = sanitizeRuntimeContext({ outer: { list: [{ [key]: "raw" }] } }) as any;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/suspicious/noExplicitAny — Risk: 55/100

Unexpected any. Specify a different type.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/suspicious/noExplicitAny` issue at packages/otlp-ingester/src/redact.test.ts:37: Unexpected any. Specify a different type.

Flagged by Autter security & observability checks.

before(async () => {
chStub = createServer((req, res) => {
let body = "";
req.on("data", (chunk) => (body += chunk));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/suspicious/noAssignInExpressions — Risk: 55/100

The assignment should not be in an expression.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/suspicious/noAssignInExpressions` issue at packages/otlp-ingester/src/redact.test.ts:74: The assignment should not be in an expression.

Flagged by Autter security & observability checks.

attributes: [
str("exception.type", "OperationalError"),
str("exception.message", `stripe rejected ${STRIPE} for jane@example.com`),
str("exception.stacktrace", 'Traceback (most recent call last):\n File "/app/pay.py", line 9, in charge\n stripe.api_key = "' + STRIPE + '"\nOperationalError: password=hunter3py'),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/useTemplate — Risk: 55/100

Template literals are preferred over string concatenation.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useTemplate` issue at packages/otlp-ingester/src/redact.test.ts:163: Template literals are preferred over string concatenation.

Flagged by Autter security & observability checks.

const bodies = [];
const server = createServer((req, res) => {
let body = "";
req.on("data", (c) => (body += c));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/suspicious/noAssignInExpressions — Risk: 55/100

The assignment should not be in an expression.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/suspicious/noAssignInExpressions` issue at packages/runtime-node/test/relay-compat.test.mjs:14: The assignment should not be in an expression.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 6 finding(s) as review threads below (🟡 6). Each carries a copy-paste AI fix prompt.

Comment thread CHANGELOG.md

### Security

- Scrub secrets and PII from exception messages, stack traces and span status messages, not only custom attributes; re-scrub every span at export so third-party instrumentations, HTTP URLs (`?token=`) and `recordException` calls are covered; scrub `LlmCallHandle.setAttributes`, `instrumentLlmClient` attributes and provider errors, and module-level captures made before `initAutterServer` (`runtime-node`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 407

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at CHANGELOG.md:7: Line length: Expected: 80; Actual: 407

Flagged by Autter security & observability checks.

Comment thread docs/COMPATIBILITY.md
gets one warning:

```text
[autter-runtime] Operation logging needs ingester >= 1.4.0; yours is 1.3.4. Upgrade the ingester: docker pull ghcr.io/autter-dev/otlp-ingester:latest and restart it (ClickHouse migrations run at boot). See https://github.com/Autter-dev/autter-runtime/blob/main/docs/COMPATIBILITY.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 285

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at docs/COMPATIBILITY.md:15: Line length: Expected: 80; Actual: 285

Flagged by Autter security & observability checks.

const HEADER_VALUE_RE =
/((?:^|[^\w-])(?:proxy-)?(?:authorization|(?:set-)?cookie)["']?\s*[:=]\s*["']?)[^"'\r\n]+/gim;
const SECRET_ASSIGNMENT_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/otlp-ingester/src/redact.ts:29:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/otlp-ingester/src/redact.ts:29: packages/otlp-ingester/src/redact.ts:29:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

const HEADER_RE =
/((^|[^\w-])(proxy-)?(authorization|(set-)?cookie)["']?\s*[:=]\s*["']?)[^"'\r\n]+/gim;
const ASSIGN_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/runtime-browser/src/index.ts:143:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/runtime-browser/src/index.ts:143: packages/runtime-browser/src/index.ts:143:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

Comment thread packages/runtime-node/src/redact.ts Outdated
* by `=` or `:`. Value ends at a delimiter so the surrounding query string
* or JSON stays readable. */
const SECRET_ASSIGNMENT_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/runtime-node/src/redact.ts:106:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/runtime-node/src/redact.ts:106: packages/runtime-node/src/redact.ts:106:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

Comment thread packages/runtime-node/src/redact.ts Outdated
if (options === false) {
return (attributes) => ({ ...(attributes ?? {}) });
const passthrough = ((attributes?: Attributes | null) => ({
...(attributes ?? {}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: unicorn(no-useless-fallback-in-spread) — Risk: 30/100

packages/runtime-node/src/redact.ts:499:4: Empty fallbacks in spreads are unnecessary

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `unicorn(no-useless-fallback-in-spread)` issue at packages/runtime-node/src/redact.ts:499: packages/runtime-node/src/redact.ts:499:4: Empty fallbacks in spreads are unnecessary

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 5 finding(s) as review threads below (🔴 1 · 🟠 4). Each carries a copy-paste AI fix prompt.

Comment thread package-lock.json
"@opentelemetry/sdk-trace-base": "^1.30.1",
"@opentelemetry/semantic-conventions": "^1.28.0"
},
"bin": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 [deterministic] Vulnerable dependency: proxy-addr@2.0.7 — CVE-2026-90711 — Risk: 85/100

proxy-addr@2.0.7 (npm) is affected by CVE-2026-90711 (GHSA-jqcg-44mw-7w3h) — critical severity. proxy-addr vulnerable to IP spoofing via IPv4-mapped IPv6 trust subnet

🛠 AI fix prompt (copy & paste into your coding agent)
Upgrade `proxy-addr` past the version affected by CVE-2026-90711, or apply the advisory's mitigation. Details: https://osv.dev/GHSA-jqcg-44mw-7w3h.

Flagged by Autter security & observability checks.

// Customer-supplied patterns extend the built-ins.
redact: { keys: /^internal_ref$/, values: [/ORD-\d{5}/g] },
});
setContext({ checkout: { cardNumber: "4111111111111111", step: "pay" } });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at packages/runtime-browser/test/redact-e2e.test.mjs:26. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

// Secrets inside exception messages, stacks, and status messages.
for (const secret of [
"hunter2pg",
"4111 1111 1111 1111",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at packages/runtime-node/test/autoflush.test.mjs:98. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

autter.captureException(
new Error("connect ECONNREFUSED postgres://admin:hunter2pg@db.internal:5432/app"),
);
autter.captureMessage(`charge failed for card 4111 1111 1111 1111 key ${STRIPE}`, "warning");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at packages/runtime-node/test/fixtures/e2e-redaction.mjs:36. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

},
{
"name": "credit card numbers (Luhn-valid), spaced and plain",
"input": "charge 4111 1111 1111 1111 declined; amex 378282246310005",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Possible PII in source: CREDIT_CARD — Risk: 72/100

Possible CREDIT_CARD on this line. Committing real personal data (or leaking it in code/config/logs) is a privacy risk.

🛠 AI fix prompt (copy & paste into your coding agent)
Remove the CREDIT_CARD value at test-vectors/redaction.json:138. If it's test data, use an obviously-fake placeholder; if it's real, purge it and rotate anything exposed.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-next/package.json:1 · build_failure

🟡 [deterministic] Build failed: @autter/runtime-next — Risk: 40/100

npm run build could not verify the @autter/runtime-next build in packages/runtime-next — this is not evidence that this PR breaks it.

DTS dist/client.d.cts 1.07 KB

src/server.ts(34,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.
src/server.ts(61,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.
src/server.ts(74,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.

Error: error occurred in dts build
    at Worker.<anonymous> (/tmp/autter-agentic-5BsNXr/node_modules/tsup/dist/index.js:1545:26)
    at Worker.emit (node:events:514:28)
    at MessagePort.<anonymous> (node:internal/worker:350:14)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:848:20)
    at MessagePort.<anonymous> (node:internal/per_context/messageport:23:28)
npm error Lifecycle script `build` failed with error:
npm error code 1
npm error path /tmp/autter-agentic-5BsNXr/packages/runtime-next
npm error workspace @autter/runtime-next@1.4.0
npm error location /tmp/autter-agentic-5BsNXr/packages/runtime-next
npm error command failed
npm error command sh -c tsup

1 attempt(s), 0 of 3 retries used.
403 Key limit exceeded (total limit). Manage it using https://openrouter.ai/workspaces/default/keys/b804e0339354b3047671bc5af58e33919e384067a558b4bf5b0669502e059e12

🛠 AI fix prompt (copy & paste into your coding agent)
Autter could not verify the @autter/runtime-next build (`npm run build` in `packages/runtime-next`) because the check environment or selected suite was unavailable: DTS dist/client.d.cts 1.07 KB

src/server.ts(34,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.
src/server.ts(61,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.
src/server.ts(74,8): error TS2307: Cannot find module '@autter/runtime-node' or its corresponding type declarations.

Error: error occu.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 1 finding(s) as review threads below (🟠 1). Each carries a copy-paste AI fix prompt.

const inserts: Record<string, Array<Record<string, unknown>>> = {};
const server = createServer((req, res) => {
let body = "";
req.on("data", (chunk) => (body += chunk));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/suspicious/noAssignInExpressions — Risk: 55/100

The assignment should not be in an expression.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/suspicious/noAssignInExpressions` issue at packages/otlp-ingester/src/server.compat.test.ts:53: The assignment should not be in an expression.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

🧪 Autter test run

Autter checked 0f054070.

This PR changes 58 source files. It ran the project's test command for the workspace this PR touched, because those suites are the fastest check that the change did not break existing behavior. It wrote 2 temporary tests for changed files that had no matching test, so the new behavior is still checked. It also executed 2 checks from the PR's test plan.

Targeted agent checks: Autter ran targeted checks against the files this PR changed — it executed uncovered test-plan items and, where a changed file had no matching test, wrote a temporary test to verify the new behavior.

Execution summary: 11 checks executed · 11 passed.

Project test commands

Scope Command Result
@autter/otlp-ingester npm run test ✅ passed · 2s

Failing tests

7 test cases failed.

  • ❌ packages/runtime-node/test/autoflush.test.mjs — the file failed before any test reported
    Why: The test expected the exit code to be 143 after a SIGTERM flush, but the observed value was 1.
    Assertion: ✖ SIGTERM with no other handler: flushes then exits 130/143 (100.900899ms)
    Repeat with: node --test 'test/autoflush.test.mjs' in packages/runtime-node
  • ❌ packages/runtime-node/test/compat.test.mjs — the file failed before any test reported
    Why: The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
    Assertion: node:internal/modules/package_json_reader:331
    Repeat with: node --test 'test/compat.test.mjs' in packages/runtime-node
  • ❌ packages/runtime-node/test/logger.test.mjs — the file failed before any test reported
    Why: The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
    Assertion: node:internal/modules/package_json_reader:331
    Repeat with: node --test 'test/logger.test.mjs' in packages/runtime-node
  • ❌ packages/runtime-node/test/redact.test.mjs — the file failed before any test reported
    Why: The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
    Assertion: node:internal/modules/package_json_reader:331
    Repeat with: node --test 'test/redact.test.mjs' in packages/runtime-node
  • ❌ packages/runtime-node/test/relay-compat.test.mjs — the file failed before any test reported
    Why: The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
    Assertion: node:internal/modules/package_json_reader:331
    Repeat with: node --test 'test/relay-compat.test.mjs' in packages/runtime-node
  • ❌ packages/runtime-node/test/relay.test.mjs — the file failed before any test reported
    Why: The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
    Assertion: node:internal/modules/package_json_reader:331
    Repeat with: node --test 'test/relay.test.mjs' in packages/runtime-node
  • ❌ packages/runtime-node/test/sinks.test.mjs — the file failed before any test reported
    Why: The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
    Assertion: node:internal/modules/package_json_reader:331
    Repeat with: node --test 'test/sinks.test.mjs' in packages/runtime-node

Autter targeted verification

10 tests executed · 10 passed.

Critical feature verification

Defense-in-depth redaction of browser error telemetry through the Node relay and ClickHouse persistence.
Could not run: Critical verification must target the checked-out PR in the sandbox, using sandbox or a loopback app URL.

Code-level simulations

Revision 0f0540704c3d · 457.1s · up to 2 scenarios in parallel

  • Node export-time redaction of third-party spans and resources — execution incomplete (code_diff, code_diff, code_diff, spec)
    Source: packages/runtime-node/src/redact-exporter.ts — links: span.links.map((link) =>
    Source: packages/runtime-node/src/redact-exporter.ts — resource: redactResource(span.resource, redactor),
    Source: packages/runtime-node/src/redact-exporter.ts — // Fail closed: a span we could not scrub is not exported.
    Source: PR description — They also scrub at export time, which covers third-party spans and URLs with ?token=.
    Could not complete: Error: Cannot run the requested build in this checkout: read-only dependencies are missing tsup, @opentelemetry/sdk-node, @opentelemetry/exporter-trace-otlp-http, and @opentelemetry/exporter-metrics-otlp-http. No dependencies were installed or modified.
  • Browser capture stays redacted through the server relay — execution incomplete (code_diff, code_diff, spec)
    Source: packages/runtime-browser/src/index.ts — if (event.context) {
    try {
    event.context = redactContext(event.context);
    Source: packages/runtime-node/src/relay.ts — const payload = sanitizeBrowserPayload(raw, redactor);
    Source: PR description — The browser relay scrubs message, stack, name and nested context.
    Ran: node '.autter/scratch/browser-relay-redaction.mjs'
    Indexed blast radius: 0 direct / 0 transitive dependents (indexed 2026-08-25T18:32:07.053Z).
    Could not complete: Error: Simulation did not emit exactly one completed assertion report.
  • Compatibility report and Node/Python doctor outcomes against local ingesters — execution incomplete (code_diff, code_diff, spec)
    Source: packages/runtime-node/src/doctor.ts — const exitCode: DoctorReport["exitCode"] = !info
    ? 2
    Source: adapters/python/compat.py — return report, 2 if info is None else 1 if issues else 0
    Source: docs/COMPATIBILITY.md — Exit codes: 0 compatible, 1 mismatch or rejected key, 2 ingester unreachable.
    Ran: node '.autter/scratch/compat-doctor-harness.mjs'
    Could not complete: Error: Simulation emitted an invalid assertion report. njected diagnostic failures are observable or propagated and cannot look like a successful compatible check.","actual":"[{"name":"Node startup remains fast and old feature warns once","passed":true,"actual":"startup…
    Source unavailable: Production route aggregates are unavailable: Runtime queries are not configured. No retained production error patterns were available for this repository.
    Coverage limitation: No production runtime IDs were supplied, so no production-backed scenarios apply.
    Coverage limitation: All integration boundaries use local fakes; these plans do not verify behavior against a real ClickHouse server, including physical table-engine, TTL, or migration-replay semantics, nor do they contact real ingesters or users.
    Coverage limitation: Scenario omitted because its source evidence could not be verified: Shared redaction contract across SDKs and the ingester
    Coverage limitation: Scenario omitted because its source evidence could not be verified: Ingester redacts legacy OTLP and browser data before fingerprinting, storage, and sink forwarding
    Coverage limitation: Scenario omitted because its source evidence could not be verified: Public compatibility report and throttled SDK sightings

Declared tests: 42 test file(s) found — 26 ran, 0 not observed in suite output, 16 did not run.

The project's command reported 13 of them. Autter ran the other 13 files one by one so every declared test has a verdict (6 passed, 7 failed).

"Did not run" means no test command that Autter executed covers the file, so nothing in it was checked.

⚠️ Test cases that did not run
  • ⛔ adapters/python/test_compat.py — no test suite covers this file; the runner command was not available in the test environment
  • ⛔ adapters/python/test_redact.py — no test suite covers this file; the runner command was not available in the test environment
  • ⛔ packages/runtime-browser/test/before-send.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-browser/test/coded-errors.test.mjs (5 cases) — no test suite covers this file
  • ⛔ packages/runtime-browser/test/csp-actions.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-browser/test/network.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-core/test/core.test.mjs (15 cases) — no test suite covers this file
  • ⛔ packages/runtime-edge/test/edge.test.mjs (7 cases) — no test suite covers this file
  • ⛔ packages/runtime-next/test/next.test.mjs (3 cases) — no test suite covers this file
  • ⛔ packages/runtime-node/test/golden.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-node/test/hook-mode.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-node/test/lifecycle.test.mjs (4 cases) — no test suite covers this file
  • ⛔ packages/runtime-node/test/logger-ingester.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-node/test/logging-only.test.mjs (1 case) — no test suite covers this file
  • ⛔ packages/runtime-node/test/operations.test.mjs (5 cases) — no test suite covers this file
  • ⛔ packages/runtime-node/test/requests.test.mjs (5 cases) — no test suite covers this file

Tests for this change

Autter ran the existing tests for 6 changed files, and it wrote 2 temporary tests for changed files that had none (2 passed, 0 failed).

Change coverage (is each changed file's behavior verified by a test?)

Changed file Related test Result
adapters/python/caught_exceptions.py adapters/python/test_redact.py ✅ existing test passes
adapters/python/compat.py adapters/python/test_compat.py ✅ existing test passes
adapters/python/redact.py adapters/python/test_redact.py ✅ existing test passes
packages/otlp-ingester/src/clickhouse.ts packages/otlp-ingester/src/server.compat.test.ts ✅ existing test passes
packages/otlp-ingester/src/compat.ts packages/otlp-ingester/src/compat.test.ts ✅ existing test passes
packages/otlp-ingester/src/config.ts packages/otlp-ingester/src/continuous-detection.test.ts ✅ no declared test — temporary test passed
packages/otlp-ingester/src/context.ts packages/otlp-ingester/src/redact.test.ts ✅ existing test passes
packages/otlp-ingester/src/index.ts — ✅ no declared test — temporary test passed
🤖 Coverage-check evidence

adapters/python/caught_exceptions.py

adapters/python/compat.py

adapters/python/redact.py

packages/otlp-ingester/src/clickhouse.ts

packages/otlp-ingester/src/compat.ts

packages/otlp-ingester/src/config.ts

packages/otlp-ingester/src/context.ts

packages/otlp-ingester/src/index.ts

Temporary tests are written under .autter/scratch/ for verification only — they are never committed to the repository.

Test plan (from the PR description)

  • ⬜ Run npm run build at the repo root and confirm npm run size -w @autter/runtime-browser stays within budget. — No build or size run provided.
  • ⬜ Run the ingester tests (redact.test.ts, compat.test.ts, server.compat.test.ts, coded-errors.test.ts), the runtime-node tests (redact.test.mjs, compat.test.mjs, doctor.test.mjs, relay-compat.test.mjs, autoflush.test.mjs), the runtime-browser tests (redact-vectors, redact-hardening, redact-e2e) and python -m pytest adapters/python. All must pass. — Only ingester package tests ran; others missing.
  • ⬜ Start the local ingester with ClickHouse from Docker Compose, then run curl -i localhost:4318/v1/compat. Check that the ingester-version header is present and that the schema level and migrations look right. — No Docker Compose or curl run.
  • ⬜ POST a /v1/browser payload using the documented curl request, with context containing {"note":"sk-<fake key>","debug":"AKIA<fake>"} and a fake JWT in message. Read the row back from ClickHouse and confirm no secret survives in message, stack, route or attributes. — No POST payload or ClickHouse row check.
  • ⬜ Send an OTLP trace whose span attributes, event attributes, link attributes and resource attributes contain a fake secret. Confirm the stored span has none, and note whether link and resource attributes are scrubbed by redact-exporter.ts. — Unit tests ran; no explicit OTLP trace send.
  • ⬜ Send the same payload through the Node browser relay and confirm the forwarded body is already redacted. — No browser relay payload send.
  • ✅ Start the ingester with AUTTER_REDACT_VALUE_PATTERNS='["internal-[0-9]{6}"]' and confirm a matching value is masked. Then set AUTTER_REDACT_VALUE_PATTERNS='not json' and confirm startup fails with a clear error. — verified by agent execution
  • ⬜ Run the doctor CLI against the local ingester using a current SDK version, then against an out-of-range version. Check that the output and exit code match docs/COMPATIBILITY.md. — No doctor CLI run.
  • ⬜ After a few ingests, query sdk_versions and ingester_info in ClickHouse. Confirm the SDK rows are present and that reportIngesterInfo writes at most once per throttle window. — No ClickHouse query after ingests.
  • ⬜ Restart the ingester against an already-migrated database to confirm the new migration re-runs without error. Also boot against a fresh database and compare the table shapes. — Migrations applied in tests; restart not confirmed.
  • ✅ Check that a fixture error produces the same fingerprint before and after scrubbing for ordinary messages, to rule out unintended issue regrouping. — verified by agent execution
🤖 Agent-executed checks

✅ Start the ingester with AUTTER_REDACT_VALUE_PATTERNS='["internal-[0-9]{6}"]' and confirm a matching value is masked. Then set AUTTER_REDACT_VALUE_PATTERNS='not json' and confirm startup fails with a clear error.
With a local fake ClickHouse HTTP sink, the ingester accepted the browser event (202) and inserted context.note as [redacted]; internal-123456 was absent from the captured row. Invalid JSON exite…

✅ Check that a fixture error produces the same fingerprint before and after scrubbing for ordinary messages, to rule out unintended issue regrouping.
All six ordinary-message stack fixtures (Go, Rust, Java, .NET, Node, Python) produced identical fingerprints before and after scrubbing. The fingerprint test suite also passed 30/30.

⬜ items could not be verified automatically and still need a manual check.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Autter product walk

Autter did not drive this change in a browser.

This PR changes a backend/API, but Autter could not find a start, dev, or run command for it, so it could not boot the service and exercise its endpoints. Autter ran targeted checks only. Add a start command (a start/dev script, or make it discoverable on the repo's "How to run this" tab), and Autter exercises the endpoints on the next push.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter blocked this PR: build. See the findings below and the full PR review for details.

@autter-dev

autter-dev Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Autter review completed — merge blocked

Autter completed its review and found at least one confirmed merge-blocking finding.

Autter blocked this PR: test. See the findings below and the full PR review for details.

Other findings explain the additional warnings, but they did not independently block this PR.

The merge gate remains blocked until the confirmed finding is resolved.

Retry

Retrying reruns the review on the same commit. If the commit is unchanged, the same finding and block may be reproduced.

  • Click Retry review on the autter/review-gate check below, or
  • Comment @autter review on this PR

Autter will post a new comment when the retry starts.

Sagnik Ghosh and others added 12 commits October 9, 2026 02:16
runtime-node and runtime-edge bundle the private runtime-core package, and
runtime-next imports runtime-node, runtime-edge and runtime-browser for its
type declarations. Building any of them alone before its siblings had been
built failed with "Could not resolve @autter/runtime-core" or TS2307, which
is what the review gate's per-package build hit.

scripts/ensure-built.mjs builds a sibling only when its dist/ is missing, so
the root build (already in dependency order) does no extra work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runtime-next imports runtime-node and runtime-browser for its type
declarations, so building it alone before them failed with TS2307, which is
what the review gate's per-package build hit. scripts/ensure-built.mjs builds a
sibling only when its dist/ is missing, so the root build does no extra work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n hostile attributes

The per-isolate queue dropped whichever record arrived last once it held
maxQueue records or 1 MB, and the summary is always emitted last, so a
request logging 250 warnings exported no summary at all. A summary now
evicts the oldest plain record, and warn/error records are capped at 50 per
request.

rt.error and rt.captureException spread the caller's attributes before
redaction, so a throwing getter or a Proxy made the user's handler throw.
They now copy fields one by one and skip ones that throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CHANGELOG says cache_creation_tokens counts are no longer masked, but only
the ingester was updated; the SDK redactor still turned them (and
cache_read_input_tokens, cache_creation_input_tokens, cached_tokens and
reasoning_tokens) into "[redacted]". Numeric counts under these keys are
kept now; non-numeric values are still masked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
liftErrorFields took the first non-empty autter.error.code across the
exception event and its span and validated it afterwards, so an invalid code
on the event (ECONNRESET) hid a valid one on the span and the error fell
back to message grouping. Same for autter.request.id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ore cutting

- JWT: \beyJ… could start a match at every "eyJ" after a "-", and each
  start rescanned the rest of the run. 64 KB of "eyJ-" took 5 s in Node,
  3.4 s in the ingester (reachable by any ingest key), 6 s in the browser
  and 1.8 s in Python. A lookbehind (a captured prefix in the browser, for
  older Safari) lets a match start only at the beginning of a run.
- The ingester caps each scrubbed string at 64 KB and cuts context values to
  their stored size before scrubbing; a 900 KB attribute was scrubbed in full
  once per exception event.
- Custom key patterns with g/y kept lastIndex between keys, so /internal/g
  skipped every other key (Node and browser). Value patterns drop y (it
  never matched mid-string) and the browser makes them global, as Node does.
- Browser, relay and the Python sampler cut text before scrubbing, which
  left half a secret at the cut ("admin:hunt"). They now scrub with 512
  chars of slack, then cut.
- A browser context with a throwing getter or revoked Proxy is dropped
  instead of throwing from captureException; a Python value whose __str__
  raises is masked.
- The card key rule masked "discard"/"scorecard", contradicting its own
  comment; it now needs a non-letter before "card".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The export-time redactor scrubbed span and event attributes but passed links,
event names and the resource through. NodeSDK's process detector puts
process.command_args on the resource (`--db=postgres://user:pass@…`) and
OTEL_RESOURCE_ATTRIBUTES can carry anything, and the resource also rides
every metrics export.

- Link attributes and event names are scrubbed; the resource is scrubbed
  once per Resource object (the OTLP serializer groups spans by resource
  identity), for traces and, via RedactingMetricExporter, metrics.
- A batch containing a span that could not be scrubbed still drops that
  span, but now reports the export as failed instead of a silent success.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Context values have no length limit, so a 1 MB string was scanned in full on
the main thread (~0.6 s, and 1.7 s for some shapes). scrubText now scans at
most 32 KB; stacks are cut to 32 000 characters after scrubbing anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@autter-dev

autter-dev Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

🤖 AI authorship

60.3% of changed code was AI-written — 0% human, 40% untracked, across 10,577 attributed line(s).

By model: claude:claude-opus-5-5 60%

Most AI-authored files:

  • packages/runtime-node/src/logger.ts — 100% AI (632 lines)
  • packages/otlp-ingester/src/coded-errors.test.ts — 100% AI (627 lines)
  • packages/runtime-node/src/requests.ts — 100% AI (613 lines)
  • packages/runtime-node/src/sinks.ts — 100% AI (529 lines)
  • packages/runtime-edge/src/index.ts — 100% AI (477 lines)

Partial coverage: some commits in this PR were not authored through the autter CLI.

Provenance measured at authorship time by the autter CLI.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🤖 Release Notes Curator

Impact: minor. Every SDK and the ingester now scrub secrets, and a new compatibility check (/v1/compat, a runtime warning and a doctor command) is added. Both are new user-facing capabilities and existing integrations keep working. One behavior change to note is that error messages containing secrets now fingerprint on their scrubbed form.

Changelog entry

Added

  • Secrets are now scrubbed everywhere. Exception messages, stack traces, span names, HTTP URLs, LLM-call data and browser context are cleaned of tokens, API keys, passwords, connection strings, card numbers and emails before they leave your app. The Node, browser and Python SDKs do this, and the ingester repeats it before storage and before forwarding to your webhook. You can add your own patterns with the redact option, redact.configure() in Python, or AUTTER_REDACT_VALUE_PATTERNS and AUTTER_REDACT_KEY_PATTERNS on the ingester.
  • Automatic SDK and ingester compatibility check. If your ingester is too old for a feature you use, the SDK warns once and tells you which version to upgrade to. Run npx @autter/runtime-node doctor --endpoint <your ingester> for a full report. Python services can use the bundled compat.py. You can turn the check off with AUTTER_COMPAT_CHECK=0.

Fixed

  • Scrubbing a long token string no longer stalls the app for seconds.

Custom agent · runs after review · configured in Autter

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 4 finding(s) as review threads below (🟠 1 · 🟡 3). Each carries a copy-paste AI fix prompt.

name: scrubText(span.name ?? "unnamed").slice(0, 1000),
kind,
status: isError ? "error" : "ok",
route: route ? normalizeRoute(route) : null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [ai] OTLP route values bypass the new scrubber before persistence — Risk: 55/100

The route is derived from untrusted OTLP attributes and only passed through normalizeRoute, which strips query strings and templates numeric/UUID/hex segments but leaves values such as /users/alice@example.com or a secret embedded in a path unchanged. This value is written directly to each span and reused for request rollups, while the new occurrence scrubber only protects occurrence fields; therefore route PII/secrets still reach ClickHouse despite the ingester-side scrubbing added by this change. Scrub the route before both the span and rollup paths (and retain the existing route normalization).

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-otlp.ts, packages/otlp-ingester/src/fingerprint.ts, packages/otlp-ingester/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

// free-text fields old SDKs and third-party OTLP senders pass
// through verbatim. Attributes were already sanitised by the
// normalisers (sanitizeRuntimeContext).
const input = scrubOccurrence(raw);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [ai] Browser filename attributes are not scrubbed before storage or forwarding — Risk: 35/100

fingerprintAll applies scrubOccurrence, but that function only replaces errorType, message, stack, and route, leaving attributes untouched. The browser normalizer puts the query-stripped event.filename directly into attributes.filename; email addresses or secret-shaped values in a filename path therefore survive this new server-side pass and are serialized into the stored occurrence attributes (and sent onward with the occurrence). Scrub the filename or sanitize all occurrence attributes before they leave the normalizer.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/normalize-browser.ts, packages/otlp-ingester/src/redact.ts, packages/otlp-ingester/src/server.ts, packages/otlp-ingester/src/clickhouse.ts
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

const pkg = createRequire(import.meta.url)("../package.json") as { version?: string };
cachedVersion = typeof pkg.version === "string" ? pkg.version : "0.0.0";
} catch {
cachedVersion = "0.0.0";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [ai] Package-version lookup failure is cached as a real version — Risk: 25/100

If loading ../package.json fails (for example, a missing or malformed package file in a deployment artifact), this catch silently caches 0.0.0 and never retries or reports the lookup failure. createIngesterApp uses that value for the compatibility report and the x-autter-ingester-version response header, so every client sees a fabricated version and can diagnose a healthy newer ingester as obsolete; the dashboard also records the false version. Preserve observability and represent an unavailable version as unknown or fail startup instead of presenting the fallback as authoritative metadata.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/otlp-ingester/src/sdk-versions.ts, packages/otlp-ingester/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Make package-version lookup failure observable and avoid caching `0.0.0` as if it were the actual ingester version; either fail startup with a clear error or propagate an explicit unknown version that compatibility consumers handle safely.

Flagged by Autter security & observability checks.

return;
}
mergeInfo(info);
for (const route of routesFor(current.features)) current.pendingProbes.add(route);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [ai] An inconclusive legacy route probe is permanently treated as pending — Risk: 25/100

If a legacy ingester returns 404 for /v1/compat but a route probe times out or otherwise fails, probeRoute returns null and fetchIngesterCompat omits that route from info.routes. runCheck nevertheless adds every feature route to pendingProbes; evaluateAndWarn then excludes pending routes from future probes, and the set is never cleared. A transient failure on the one-time startup check therefore prevents this process from ever detecting or warning that the legacy ingester lacks the feature route. Only mark successful/in-flight probes pending and clear the marker after an inconclusive result so it can be retried.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-node/src/compat.ts
🛠 AI fix prompt (copy & paste into your coding agent)

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor
⚠️ 1 unconfirmed finding(s) — flagged by a detector but not proven by Autter's verification pass

Inline comments are reserved for findings that survived verification. These are plausible but could not be confirmed from the available context, so they are listed here as FYIs instead — review the ones that look real to you.

  • 🟡 Unconfigured storage is reported as compatible (risk 35/100) — packages/otlp-ingester/src/compat.ts:237 — The behaviour is real: only schema status 'failed' or 'ready' with missing migrations produces an issue. 'unconfigured' and 'pending' produce none, and server.ts authenticate returns 503 when storage is unconfigured. server.compat.test.ts:91-94 asserts status 'unconfigured' with no issues, so this looks like a deliberate design in which compat covers versions and migrations and /healthz reports st

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 1 finding(s) as review threads below (🟡 1). Each carries a copy-paste AI fix prompt.

Comment thread packages/runtime-node/src/redact.ts Outdated
/** `Authorization: …`, `Cookie: …`, `Set-Cookie: …` (raw header text, JSON,
* util.inspect): the whole value goes, since cookies and auth schemes
* contain spaces and semicolons. */
const HEADER_VALUE_RE =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [ai] Cookie/Authorization header redaction stops at the first quote, leaking credentials in all SDK scrubbers — Risk: 30/100

The shared Authorization: / Cookie: / Set-Cookie: header-text pattern masks only up to the first " or ' character. Any header value that contains a quote leaves the rest of the credential in clear text. This affects the Node SDK, browser SDK, Python adapter and ingester scrubbers identically, and the shared test vectors never exercise it.

HEADER_VALUE_RE is /((?:^|[^\w-])(?:proxy-)?(?:authorization|(?:set-)?cookie)["']?\s*[:=]\s*["']?)[^"'\r\n]+/gim. The optional opening quote is consumed into the head group, and the value is [^"'\r\n]+, so matching ends at the first quote character inside the value. Results from running the Node redactor:

  • Cookie: theme=dark; session="SECRETVALUE1234"; lang=en becomes Cookie: [redacted]"SECRETVALUE1234"; lang=en.
  • Authorization: Digest username="bob", realm="api", response="6629..." becomes Authorization: [redacted]"bob", realm="api", response="6629...".
  • {\"headers\":{\"cookie\":\"sid=SECRETVALUE\"}} is untouched, because the backslash between the key and its closing quote prevents ["']?\s*[:=] from matching.

The later SECRET_ASSIGNMENT_RE pass does not rescue these: it only matches secret-named keys such as session_id, and session="..." is not one. The same regex is duplicated in the ingester, browser and Python implementations, so the server-side backstop leaks identically. The fix replaces the value group with a quote-aware alternation (a double-quoted string with escapes, a single-quoted string, or the rest of the line), tolerates a backslash before the key's closing quote, and re-emits the surrounding quote characters when masking. It adds no nested quantifier on the same character class, and a 60k-char adversarial input ran in under 5 ms.

  1. Call redactText from packages/runtime-node/src/redact.ts (or redact_text in adapters/python/redact.py) with Cookie: theme=dark; session="SECRETVALUE1234"; lang=en.
  2. Observe that "SECRETVALUE1234" survives in the output.
  3. Call it with Authorization: Digest username="bob", realm="api", response="6629fae49393a05397450978507c4ef1" and observe that everything after Digest survives.
  4. Call it with the JSON-escaped string {\"cookie\":\"sid=SECRETVALUE\"} and observe it is returned unchanged.

Evidence:
Before the fix the output is Cookie: [redacted]"SECRETVALUE1234"; lang=en. After the fix the output is Cookie: [redacted], Authorization: "[redacted]" retry, and {\"cookie\":[redacted]. Node (95), browser (44) and ingester (117) test suites and the Python unit tests pass with the fix and the two new shared vectors.

Checked key-name matching, which still masks structured cookie/authorization attributes wholesale, so only free-text header dumps are affected. The common unquoted Cookie: a=b; c=d and Authorization: Bearer x forms are redacted correctly. The leak needs a quote in the header value, or JSON-escaped header text.

Proof of concept:

import { redactText } from "./packages/runtime-node/src/redact.ts";
for (const s of [
 'Cookie: theme=dark; session="SECRETVALUE1234"; lang=en',
 'Authorization: Digest username="bob", realm="api", response="6629fae49393a05397450978507c4ef1"',
 '{\\"cookie\\":\\"sid=SECRETVALUE\\"}',
]) console.log(redactText(s));
🛠 AI fix prompt (copy & paste into your coding agent)
Replace the header value capture with a quote-aware alternation in all four implementations (Node, browser, ingester, Python), allow an optional backslash after the header name, and re-emit the surrounding quote when masking. Add the quoted-cookie and quoted-Authorization cases to the shared test-vectors/redaction.json so every implementation is checked for parity.

Impact to account for:
Credentials embedded in header text inside exception messages, stacks, URLs or logs are exported to the telemetry backend, ClickHouse and the sink webhook unredacted. Demonstrated leaks: the remaining cookies after a quoted cookie (`session="..."`), the full RFC 7616 Digest `Authorization` parameters (username, nonce, response), and every JSON-escaped header dump (`{\"cookie\":\"sid=...\"}`, the form produced by double-serialised JSON). Impact is limited to secrets that happen to appear as header text in strings, and not every deployment emits quoted cookie values, so severity is low.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter blocked this PR: . See the findings below and the full PR review for details.

Conflicts resolve to this branch's integration of #25 and #26, with #22's
beforeSend guard re-applied to the browser SDK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sagnik11
sagnik11 merged commit d20942e into main Oct 8, 2026
1 check passed
@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🤖 Release Notes Curator

Impact: minor. This adds user-facing capabilities and doesn't break the public API. The additions are secret scrubbing in the browser SDK, the relay and the Python adapter, a new GET /v1/compat endpoint, and a doctor command. Scrubbing is on by default and the new options are additive.

Changelog entry

Security

  • Secrets and personal data are now scrubbed from exception messages, stack traces and span status messages, not only from custom attributes. This applies in the Node SDK, the browser SDK, the browser relay, the Python adapter and the ingester. Connection strings, API keys and tokens, auth headers, card numbers and emails are masked before anything is exported or stored. You can add your own patterns, and the browser SDK has a new redact option.

Added

  • Version compatibility checks. The Node SDK now warns once at startup if your ingester is too old for a feature you're using. Run npx @autter/runtime-node doctor --endpoint <ingester URL> for a full report on SDK, ingester and schema versions. The ingester also exposes GET /v1/compat, and Python services can use the new compat.py helper. Upgrade the ingester before the SDKs.

Custom agent · runs after review · configured in Autter

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 3 finding(s) as review threads below (🟡 3). Each carries a copy-paste AI fix prompt.

* adapters/python/redact.py.
*/

type AttrValue =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: eslint(no-unused-vars) — Risk: 30/100

packages/runtime-core/src/redact.ts:25:6: Type alias 'AttrValue' is declared but never used.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-unused-vars)` issue at packages/runtime-core/src/redact.ts:25: packages/runtime-core/src/redact.ts:25:6: Type alias 'AttrValue' is declared but never used.

Flagged by Autter security & observability checks.

* by `=` or `:`. Value ends at a delimiter so the surrounding query string
* or JSON stays readable. */
const SECRET_ASSIGNMENT_RE =
/(password|passwd|pwd|passphrase|secret|token|api[_-]?key|apikey|access[_-]?key|private[_-]?key|credential|signature|session[_-]?id|sessionid|ssn)(["']?\s*[:=]\s*)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'&,;)}\]\[<>]+)/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: eslint(no-useless-escape) — Risk: 30/100

packages/runtime-core/src/redact.ts:108:203: Unnecessary escape character '['

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `eslint(no-useless-escape)` issue at packages/runtime-core/src/redact.ts:108: packages/runtime-core/src/redact.ts:108:203: Unnecessary escape character '['

Flagged by Autter security & observability checks.

if (options === false) {
return (attributes) => ({ ...attributes });
const passthrough = ((attributes?: Attributes | null) => ({
...(attributes ?? {}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] oxlint: unicorn(no-useless-fallback-in-spread) — Risk: 30/100

packages/runtime-core/src/redact.ts:509:4: Empty fallbacks in spreads are unnecessary

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the oxlint `unicorn(no-useless-fallback-in-spread)` issue at packages/runtime-core/src/redact.ts:509: packages/runtime-core/src/redact.ts:509:4: Empty fallbacks in spreads are unnecessary

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 1 finding(s) as review threads below (🟠 1). Each carries a copy-paste AI fix prompt.

Comment thread package-lock.json
"@opentelemetry/sdk-trace-base": "^1.30.1",
"@opentelemetry/semantic-conventions": "^1.28.0"
},
"bin": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [deterministic] Vulnerable dependency: @grpc/grpc-js@1.14.4 — CVE-2026-101916 — Risk: 75/100

@grpc/grpc-js@1.14.4 (npm) is affected by CVE-2026-101916 (GHSA-m9gg-hp2v-232j) — high severity. @grpc/grpc-js: In certain configurations, getAuthContext can return unauthorized certificates as though they were authorized

🛠 AI fix prompt (copy & paste into your coding agent)
Upgrade `@grpc/grpc-js` past the version affected by CVE-2026-101916, or apply the advisory's mitigation. Details: https://osv.dev/GHSA-m9gg-hp2v-232j.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 3 finding(s) as review threads below (🟠 2 · 🟡 1). Each carries a copy-paste AI fix prompt.

resultCallback({ code: ExportResultCode.FAILED, error: error as Error });
return;
}
this.inner.export({ ...metrics, resource }, resultCallback);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [ai] Metric datapoint attributes bypass the redactor — Risk: 65/100

The metric exporter only scrubs the resource and then forwards the original ResourceMetrics with all scopeMetrics unchanged. Those metric datapoints can contain attributes supplied by application code through the SDK's meter provider, not only the low-cardinality attributes produced internally. A datapoint such as { password: "secret" } therefore reaches the OTLP exporter and ingester without the redaction promised for telemetry leaving the process. Scrub datapoint attributes (and other free-text metric fields that can carry attributes) before forwarding.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-node/src/server.ts, packages/runtime-node/src/redact-exporter.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Transform every metric datapoint's attributes with the active redactor before calling the inner exporter; preserve the metric values and aggregation data.

Flagged by Autter security & observability checks.

Comment thread adapters/python/redact.py
)
]
# Numeric GenAI usage counters keep their value even though "token" matches.
_USAGE_KEY = re.compile(r"(^|\.)(input|output|total|prompt|completion)_?tokens$|token_count$", re.I)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 [ai] Python redaction masks valid GenAI usage counters — Risk: 54/100

The usage-counter exemption only recognizes input/output/total/prompt/completion token keys and token_count. Other canonical counters such as cache_read_tokens, cache_creation_tokens, cached_tokens, reasoning_tokens, and gen_ai.usage.cache_read_input_tokens do not match this regex, while _SENSITIVE_KEYS matches their token substring. Consequently _redact_value replaces their numeric values with [redacted], so applications using the Python adapter's recommended redact_attributes path lose those usage values before export and downstream cost/usage tracking cannot recover them. The Node redactor explicitly preserves these canonical counters.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: adapters/python/redact.py, packages/runtime-core/src/redact.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Expand the Python usage-key exemption to cover the same canonical non-negative numeric token counters preserved by the runtime-core redactor, while continuing to mask arbitrary sensitive token fields.

Flagged by Autter security & observability checks.

);
if (unprobed.length) {
const current = state;
for (const route of unprobed) current.pendingProbes.add(route);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [ai] Failed legacy-route probe permanently suppresses compatibility warning — Risk: 35/100

When a legacy ingester has no /v1/compat endpoint, a route probe can time out or fail to connect; probeRoute represents that as null. This code leaves the route in pendingProbes, while the following result loop omits null results from info.routes. Later calls to evaluateAndWarn filter out routes already in pendingProbes, so the route is never retried and the caller gets no incompatibility warning even if the legacy ingester does not support the feature and drops its data. Clear the pending marker on indeterminate results and allow a bounded retry or surface the check as unknown with observable diagnostics.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: packages/runtime-node/src/sinks.ts, packages/runtime-node/src/compat.ts, packages/otlp-ingester/src/compat-manifest.json
🛠 AI fix prompt (copy & paste into your coding agent)
Ensure legacy-route probes that return null do not remain permanently pending: clear pending state and permit a bounded retry, or expose/log an explicit unknown check result so callers do not mistake an unchecked route for compatibility.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-node/test/autoflush.test.mjs:1 · test_failure

🟡 [deterministic] Tests failed: packages/runtime-node/test/autoflush.test.mjs — Risk: 40/100

packages/runtime-node/test/autoflush.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/autoflush.test.mjs'.

Failing tests

  • the file failed before any test reported — The test expected the exit code to be 143 after a SIGTERM flush, but the observed value was 1.
✖ SIGTERM with no other handler: flushes then exits 130/143 (100.900899ms)
✖ second signal exits immediately instead of waiting for a slow flush (83.498398ms)
✖ SIGTERM coexists with the app's own handler — app exit code wins (83.945048ms)
✖ beforeExit flush completes inside the natural-exit window (85.885683ms)
✖ e2e: captured exception attributes are redacted on the wire (85.508106ms)
✖ e2e: uncaught exception flushes telemetry before exiting with Node's crash code (85.803895ms)
✖ an application's existing uncaught exception handler keeps its behavior (81.46824ms)
ℹ tests 7
ℹ suites 0
ℹ pass 0
ℹ fail 7
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 714.066921

✖ failing tests:

test at test/autoflush.test.mjs:50:1
✖ SIGTERM with no other handler: flushes then exits 130/143 (100.900899ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
  
  1 !== 143
  
      at TestContext.<anonymous> (file:///tmp/autter-agentic-QiOanc/packages/runtime-node/test/autoflush.test.mjs:52:9)
      at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
      at async Test.run (node:internal/test_runner/test:1409:7)
      at async startSubtestAfterBootst…
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/autoflush.test.mjs fails when run with `node --test 'test/autoflush.test.mjs'`: ✖ SIGTERM with no other handler: flushes then exits 130/143 (100.900899ms)
✖ second signal exits immediately instead of waiting for a slow flush (83.498398ms)
✖ SIGTERM coexists with the app's own handler — app exit code wins (83.945048ms)
✖ beforeExit flush completes inside the natural-exit window (85.885683ms)
✖ e2e: captured exception attributes are redacted on the wire (85.508106ms)
✖ e2e: unc. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-node/test/logger.test.mjs:1 · test_failure

🟡 [deterministic] Tests failed: packages/runtime-node/test/logger.test.mjs — Risk: 40/100

packages/runtime-node/test/logger.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/logger.test.mjs'.

Failing tests

  • the file failed before any test reported — The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageResolve (node:internal/modules/esm/resolve:784:25)
    at moduleResolve (node:internal/modules/esm/resolve:873:18)
    at defaultResolve (node:internal/modules/esm/resolve:1006:11)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:705:20)
    at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:725:38)
    at ModuleLoader.resolveSync (node:internal/modules/esm/loader:763:56)
    at #resolve (node:internal/modules/esm/loader:687:17)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:607:35)
    at ModuleJob.syncLink (node:internal/modules/esm/module_job:276:33) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v24.21.0
✖ test/logger.test.mjs (94.07786ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1…
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/logger.test.mjs fails when run with `node --test 'test/logger.test.mjs'`: node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageRe. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-node/test/redact.test.mjs:1 · test_failure

🟡 [deterministic] Tests failed: packages/runtime-node/test/redact.test.mjs — Risk: 40/100

packages/runtime-node/test/redact.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/redact.test.mjs'.

Failing tests

  • the file failed before any test reported — The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageResolve (node:internal/modules/esm/resolve:784:25)
    at moduleResolve (node:internal/modules/esm/resolve:873:18)
    at defaultResolve (node:internal/modules/esm/resolve:1006:11)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:705:20)
    at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:725:38)
    at ModuleLoader.resolveSync (node:internal/modules/esm/loader:763:56)
    at #resolve (node:internal/modules/esm/loader:687:17)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:607:35)
    at ModuleJob.syncLink (node:internal/modules/esm/module_job:276:33) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v24.21.0
✖ test/redact.test.mjs (86.264296ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms …
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/redact.test.mjs fails when run with `node --test 'test/redact.test.mjs'`: node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageRe. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-node/test/relay.test.mjs:1 · test_failure

🟡 [deterministic] Tests failed: packages/runtime-node/test/relay.test.mjs — Risk: 40/100

packages/runtime-node/test/relay.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/relay.test.mjs'.

Failing tests

  • the file failed before any test reported — The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageResolve (node:internal/modules/esm/resolve:784:25)
    at moduleResolve (node:internal/modules/esm/resolve:873:18)
    at defaultResolve (node:internal/modules/esm/resolve:1006:11)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:705:20)
    at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:725:38)
    at ModuleLoader.resolveSync (node:internal/modules/esm/loader:763:56)
    at #resolve (node:internal/modules/esm/loader:687:17)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:607:35)
    at ModuleJob.syncLink (node:internal/modules/esm/module_job:276:33) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v24.21.0
✖ test/relay.test.mjs (95.020921ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1…
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/relay.test.mjs fails when run with `node --test 'test/relay.test.mjs'`: node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageRe. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

packages/runtime-node/test/sinks.test.mjs:1 · test_failure

🟡 [deterministic] Tests failed: packages/runtime-node/test/sinks.test.mjs — Risk: 40/100

packages/runtime-node/test/sinks.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/sinks.test.mjs'.

Failing tests

  • the file failed before any test reported — The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageResolve (node:internal/modules/esm/resolve:784:25)
    at moduleResolve (node:internal/modules/esm/resolve:873:18)
    at defaultResolve (node:internal/modules/esm/resolve:1006:11)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:705:20)
    at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:725:38)
    at ModuleLoader.resolveSync (node:internal/modules/esm/loader:763:56)
    at #resolve (node:internal/modules/esm/loader:687:17)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:607:35)
    at ModuleJob.syncLink (node:internal/modules/esm/module_job:276:33) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v24.21.0
✖ test/sinks.test.mjs (88.946146ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 9…
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/sinks.test.mjs fails when run with `node --test 'test/sinks.test.mjs'`: node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageRe. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter posted 2 finding(s) as review threads below (🟡 2). Each carries a copy-paste AI fix prompt.

@@ -0,0 +1,218 @@
import assert from "node:assert/strict";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] Tests failed: packages/runtime-node/test/compat.test.mjs — Risk: 40/100

packages/runtime-node/test/compat.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/compat.test.mjs'.

Failing tests

  • the file failed before any test reported — The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageResolve (node:internal/modules/esm/resolve:784:25)
    at moduleResolve (node:internal/modules/esm/resolve:873:18)
    at defaultResolve (node:internal/modules/esm/resolve:1006:11)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:705:20)
    at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:725:38)
    at ModuleLoader.resolveSync (node:internal/modules/esm/loader:763:56)
    at #resolve (node:internal/modules/esm/loader:687:17)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:607:35)
    at ModuleJob.syncLink (node:internal/modules/esm/module_job:276:33) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v24.21.0
✖ test/compat.test.mjs (95.563615ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms …
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/compat.test.mjs fails when run with `node --test 'test/compat.test.mjs'`: node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageRe. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@@ -0,0 +1,68 @@
// Relay-only process (no initAutterServer): the relay checks browser

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [deterministic] Tests failed: packages/runtime-node/test/relay-compat.test.mjs — Risk: 40/100

packages/runtime-node/test/relay-compat.test.mjs fails. The project's own test command never reported this file, so Autter ran it on its own with node --test 'test/relay-compat.test.mjs'.

Failing tests

  • the file failed before any test reported — The build output tries to import @opentelemetry/exporter-metrics-otlp-http but the package is not found in the environment.
node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageResolve (node:internal/modules/esm/resolve:784:25)
    at moduleResolve (node:internal/modules/esm/resolve:873:18)
    at defaultResolve (node:internal/modules/esm/resolve:1006:11)
    at #cachedDefaultResolve (node:internal/modules/esm/loader:705:20)
    at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:725:38)
    at ModuleLoader.resolveSync (node:internal/modules/esm/loader:763:56)
    at #resolve (node:internal/modules/esm/loader:687:17)
    at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:607:35)
    at ModuleJob.syncLink (node:internal/modules/esm/module_job:276:33) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Node.js v24.21.0
✖ test/relay-compat.test.mjs (85.056993ms)
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ durati…
🛠 AI fix prompt (copy & paste into your coding agent)
The test file packages/runtime-node/test/relay-compat.test.mjs fails when run with `node --test 'test/relay-compat.test.mjs'`: node:internal/modules/package_json_reader:331
  throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
        ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@opentelemetry/exporter-metrics-otlp-http' imported from /tmp/autter-agentic-QiOanc/packages/runtime-node/dist/index.js
    at Object.getPackageJSONURL (node:internal/modules/package_json_reader:331:9)
    at packageRe. Fix the code (or the test if it is genuinely stale) so it passes.

Flagged by Autter security & observability checks.

@autter-dev autter-dev Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Autter blocked this PR: test. See the findings below and the full PR review for details.

@autter-dev

autter-dev Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Autter task list

  • Replace secret-shaped Postgres, MongoDB and MySQL URLs in redaction fixtures (test-vectors/redaction.json, adapters/python/test_redact.py) - Replace the credentialed Postgres, MongoDB and MySQL connection URLs in test-vectors/redaction.json and adapters/python/test_redact.py with clearly fake placeholder credentials (e.g. user:FAKE_PASSWORD@example.invalid), then update the matching expected outputs so all four vector suites still pass.
  • Make the JWT and PEM private key fixtures obviously fake (test-vectors/redaction.json) - Replace the JWT-shaped value (line 6) and the PEM private key block (line 103) in test-vectors/redaction.json with clearly synthetic values, such as a truncated or placeholder key body, that still exercise the JWT and private-key redaction rules.
  • Remove credential-like values from the e2e redaction fixture (packages/runtime-node/test/fixtures/e2e-redaction.mjs) - Replace the Redis connection URL (line 42) and the generic API key (line 50) in packages/runtime-node/test/fixtures/e2e-redaction.mjs with clearly fake placeholders, or build them at runtime from fragments, while still matching the redaction patterns under test.

Generated from PR diff, blast radius, and context.

Issues found

  1. Hardcoded secret · risk 100/100 · adapters/python/test_redact.py:52 — A Postgres connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast ra…
  2. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:51 — A MongoDB connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast rad…
  3. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:61 — A MySQL connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radiu…
  4. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:103 — A PEM private key block appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is e…
  5. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:148 — A Postgres connection URL with credentials appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast ra…
  6. Hardcoded secret · risk 100/100 · test-vectors/redaction.json:6 — A JWT-shaped value appears to be hard-coded in source. Rotate the value and move it to a secret manager / environment variable. Blast radius — if this is exploi…
  7. Database connection URL with embedded credentials · risk 100/100 · adapters/python/test_redact.py:52 — A Postgres connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this cre…
  8. Private key in source · risk 100/100 · test-vectors/redaction.json:103 — A private key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it casca…
  9. Database connection URL with embedded credentials · risk 100/100 · test-vectors/redaction.json:61 — A MySQL connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this creden…
  10. API key in source · risk 90/100 · packages/runtime-node/test/fixtures/e2e-redaction.mjs:50 — A generic api key appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this credential is exploited it c…
  11. Database connection URL with embedded credentials · risk 90/100 · packages/runtime-node/test/fixtures/e2e-redaction.mjs:42 — A Redis connection URL with credentials appears to be hard-coded in source. Treat the credential as compromised and rotate it now. Blast radius — if this creden…

135 additional non-blocking finding(s) are available in the Autter review.

Also detected but not listed above: 118 finding(s) dismissed as likely false positives by verification — see the Autter review dashboard for their verdicts.

🛠 Fix options

Check one option and Autter will start a fix run for the unresolved issues above.

  • One PR with all unresolved fixes
  • One independent PR per unresolved issue

Checking a box triggers the fix run immediately — Autter comments back with the issues being fixed and the branch created for each.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant