Redact runtime capabilities and require the SDK isolation check

HTTP request logs retained the runtime GitHub capability header. Add it to the shared redaction policy and cover success, denied, and failed requests with canary credentials.

Run the real optional Sentry SDK regression in a dedicated CI job with the audited peer installed outside the workspace. Require the SDK in that job so missing installation cannot silently skip the regression.

Validation: 123 focused tests, the canonical real-SDK CI command, server typecheck, module boundaries, YAML parse, and secret scans passed.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Devin Foley
2026-09-22 12:32:18 -07:00
co-authored by Paperclip
parent af846cfd8e
commit c9db03bcab
4 changed files with 97 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
name: Sentry SDK contract
on:
pull_request:
paths:
- .github/workflows/sentry-contract.yml
- server/package.json
- server/src/sentry*.ts
- server/src/peer-version-check.ts
- server/src/__tests__/*sentry*.test.ts
push:
branches: [master]
paths:
- .github/workflows/sentry-contract.yml
- server/package.json
- server/src/sentry*.ts
- server/src/peer-version-check.ts
- server/src/__tests__/*sentry*.test.ts
permissions:
contents: read
concurrency:
group: sentry-contract-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
sentry-contract:
name: Real Sentry SDK isolation
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24
package-manager-cache: false
- name: Setup pnpm
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
with:
version: 9.15.4
- name: Install workspace dependencies
run: pnpm install --frozen-lockfile
- name: Install the audited optional SDK outside the workspace
shell: bash
run: |
sentry_version=$(node -p 'require("./server/package.json").peerDependencies["@sentry/node"]')
npm install --prefix "$RUNNER_TEMP/sentry-contract-sdk" --ignore-scripts --no-audit --no-fund --package-lock=false "@sentry/node@$sentry_version"
- name: Verify run failure isolation with the real SDK
env:
NODE_PATH: ${{ runner.temp }}/sentry-contract-sdk/node_modules
PAPERCLIP_REQUIRE_SENTRY_TEST_SDK: "1"
run: pnpm --filter @paperclipai/server exec vitest run src/__tests__/run-failure-sentry-real-sdk.test.ts
@@ -399,6 +399,35 @@ describe("HTTP logger redaction", () => {
expect(log.res.headers["set-cookie"]).toBe("[Redacted]");
});
it.each([200, 403, 500])("redacts runtime GitHub capabilities from HTTP %i logs", async (status) => {
const capability = "runtime-github-capability-canary";
const chunks: string[] = [];
const stream = new Writable({
write(chunk, _encoding, callback) {
chunks.push(chunk.toString());
callback();
},
});
const app = express();
app.use(createHttpLogger(pino({ redact: [...HTTP_LOG_REDACT_PATHS] }, stream)));
app.post("/runtime-tools/github/credentials", (_req, res) => {
res.status(status).json({ status });
});
await request(app)
.post("/runtime-tools/github/credentials")
.set("X-Paperclip-Github-Capability", capability)
.send({})
.expect(status);
const output = chunks.join("");
expect(output).not.toContain(capability);
const log = JSON.parse(output.trim());
expect(log.req.headers["x-paperclip-github-capability"]).toBe("[Redacted]");
expect(log.req.url).toBe("/runtime-tools/github/credentials");
expect(log.res.statusCode).toBe(status);
});
it("drops OAuth callback query data from the message and structured request", async () => {
const chunks: string[] = [];
const stream = new Writable({
@@ -20,6 +20,10 @@ const sentryPackage = (() => {
}
})();
if (process.env.PAPERCLIP_REQUIRE_SENTRY_TEST_SDK === "1" && !sentryPackage) {
throw new Error("The Sentry SDK contract job requires the audited optional peer");
}
afterEach(async () => {
await sentryPackage?.close(2000);
vi.unstubAllEnvs();
@@ -10,6 +10,8 @@ export const HTTP_LOG_REDACT_PATHS = [
'req.headers["x-csrf-token"]',
'req.headers["x-xsrf-token"]',
'req.headers["x-api-key"]',
// Runtime GitHub capabilities authorize credential acquisition for a live run.
'req.headers["x-paperclip-github-capability"]',
// Telegram's optional webhook verification header is a reusable bearer
// secret sent on every provider callback.
'req.headers["x-telegram-bot-api-secret-token"]',