@indigoai-us/hq-cli 5.77.14 → 5.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/assets/scaffold/core/scripts/archive-old-threads.sh +86 -0
- package/assets/scaffold/core/scripts/backfill-company-skill-mirrors.sh +73 -0
- package/assets/scaffold/core/scripts/backfill-workspace-mirror.sh +51 -0
- package/assets/scaffold/core/scripts/codex-skill-bridge.sh +550 -0
- package/assets/scaffold/core/scripts/detect-stale-core-policy-mirror.sh +185 -0
- package/assets/scaffold/core/scripts/hq-status-summary.sh +187 -0
- package/assets/scaffold/core/scripts/ontology-readme-drift.sh +264 -0
- package/assets/scaffold/core/scripts/qmd-reindex-after-sync.sh +93 -0
- package/assets/scaffold/core/scripts/rebuild-all-indexes.sh +69 -0
- package/assets/scaffold/core/scripts/rebuild-companies-index.sh +206 -0
- package/assets/scaffold/core/scripts/rebuild-company-knowledge-index.sh +127 -0
- package/assets/scaffold/core/scripts/rebuild-orchestrator-index.sh +86 -0
- package/assets/scaffold/core/scripts/rebuild-projects-index.sh +105 -0
- package/assets/scaffold/core/scripts/rebuild-public-knowledge-index.sh +83 -0
- package/assets/scaffold/core/scripts/rebuild-reports-index.sh +114 -0
- package/assets/scaffold/core/scripts/rebuild-social-drafts-index.sh +135 -0
- package/assets/scaffold/core/scripts/rebuild-threads-index.sh +82 -0
- package/assets/scaffold/core/scripts/rebuild-workers-index.sh +97 -0
- package/assets/scaffold/core/scripts/resize-screenshot.sh +47 -0
- package/assets/scaffold/core/scripts/token-usage-report.sh +254 -0
- package/assets/scaffold/core/scripts/worktree.sh +136 -0
- package/dist/commands/agents.js +28 -12
- package/dist/commands/api-keys.js +100 -20
- package/dist/commands/core.d.ts +90 -0
- package/dist/commands/core.js +279 -0
- package/dist/commands/files-browse.d.ts +21 -0
- package/dist/commands/files-browse.js +145 -24
- package/dist/commands/files.js +33 -7
- package/dist/commands/meetings.js +16 -9
- package/dist/commands/members.js +16 -5
- package/dist/commands/pack-install.d.ts +14 -0
- package/dist/commands/pack-install.js +42 -2
- package/dist/commands/pkg-install.js +39 -2
- package/dist/commands/run.js +6 -2
- package/dist/commands/secrets.js +120 -65
- package/dist/main.js +6 -0
- package/dist/utils/api-key-command-gate.d.ts +45 -0
- package/dist/utils/api-key-command-gate.js +51 -0
- package/dist/utils/hq-roots.d.ts +91 -0
- package/dist/utils/hq-roots.js +212 -0
- package/dist/utils/resolve-vault-credential.d.ts +63 -3
- package/dist/utils/resolve-vault-credential.js +152 -6
- package/dist/utils/run-bundled-script.d.ts +66 -0
- package/dist/utils/run-bundled-script.js +80 -0
- package/dist/utils/vault-api.d.ts +21 -0
- package/dist/utils/vault-api.js +74 -3
- package/package.json +7 -1
- package/.claude/policies/hq-cli-interactive-reads-use-sts-vend.md +0 -49
- package/.github/workflows/ci.yml +0 -46
- package/.github/workflows/publish.yml +0 -36
- package/.github/workflows/scripts/smoke-test-pkg.sh +0 -97
- package/e2e/cli.test.ts +0 -128
- package/eslint.config.js +0 -37
- package/pnpm-workspace.yaml +0 -4
- package/scripts/chmod-bins.mjs +0 -49
- package/scripts/generate-dsn.mjs +0 -26
- package/scripts/generate-scan-packages-table.mjs +0 -113
- package/scripts/smoke-sources-signals.sh +0 -103
- package/src/bin/hq-auth-refresh.ts +0 -43
- package/src/cli-version.ts +0 -13
- package/src/commands/__fixtures__/make-tar.ts +0 -126
- package/src/commands/_patterns.ts +0 -10
- package/src/commands/add.ts +0 -75
- package/src/commands/agents.test.ts +0 -527
- package/src/commands/agents.ts +0 -923
- package/src/commands/api-keys.test.ts +0 -291
- package/src/commands/api-keys.ts +0 -382
- package/src/commands/artifact-verify.test.ts +0 -177
- package/src/commands/auth.test.ts +0 -82
- package/src/commands/auth.ts +0 -213
- package/src/commands/billing.test.ts +0 -158
- package/src/commands/billing.ts +0 -146
- package/src/commands/channels.test.ts +0 -74
- package/src/commands/channels.ts +0 -91
- package/src/commands/cloud-demote.test.ts +0 -401
- package/src/commands/cloud-demote.ts +0 -278
- package/src/commands/cloud-provision.test.ts +0 -1117
- package/src/commands/cloud-provision.ts +0 -942
- package/src/commands/cloud.pull-all.test.ts +0 -711
- package/src/commands/cloud.pull-per-company.test.ts +0 -188
- package/src/commands/cloud.push-all.test.ts +0 -485
- package/src/commands/cloud.scope-excluded-warning.test.ts +0 -22
- package/src/commands/cloud.selectors.test.ts +0 -208
- package/src/commands/cloud.status.test.ts +0 -160
- package/src/commands/cloud.test.ts +0 -41
- package/src/commands/cloud.ts +0 -2130
- package/src/commands/company.test.ts +0 -202
- package/src/commands/company.ts +0 -148
- package/src/commands/creators.test.ts +0 -60
- package/src/commands/creators.ts +0 -117
- package/src/commands/crm.test.ts +0 -179
- package/src/commands/crm.ts +0 -236
- package/src/commands/db-migrate.ts +0 -55
- package/src/commands/db-provision.ts +0 -114
- package/src/commands/db-sql.ts +0 -124
- package/src/commands/db-status.ts +0 -108
- package/src/commands/db.ts +0 -26
- package/src/commands/dm.test.ts +0 -748
- package/src/commands/dm.ts +0 -1226
- package/src/commands/feedback.test.ts +0 -413
- package/src/commands/feedback.ts +0 -169
- package/src/commands/files-browse.test.ts +0 -1249
- package/src/commands/files-browse.ts +0 -1506
- package/src/commands/files-delete.test.ts +0 -484
- package/src/commands/files-recovery.test.ts +0 -370
- package/src/commands/files.test.ts +0 -722
- package/src/commands/files.ts +0 -1446
- package/src/commands/group-grants.test.ts +0 -330
- package/src/commands/group-grants.ts +0 -455
- package/src/commands/groups.test.ts +0 -44
- package/src/commands/groups.ts +0 -368
- package/src/commands/integrations.test.ts +0 -633
- package/src/commands/integrations.ts +0 -507
- package/src/commands/list.ts +0 -85
- package/src/commands/login.ts +0 -52
- package/src/commands/logout.ts +0 -30
- package/src/commands/marketplace-install.test.ts +0 -543
- package/src/commands/marketplace-security.test.ts +0 -646
- package/src/commands/mcp-registration.test.ts +0 -2787
- package/src/commands/mcp-registration.ts +0 -2612
- package/src/commands/mcp-status.test.ts +0 -483
- package/src/commands/mcp-status.ts +0 -575
- package/src/commands/mcp-status.us011.test.ts +0 -243
- package/src/commands/meetings.test.ts +0 -522
- package/src/commands/meetings.ts +0 -789
- package/src/commands/members.test.ts +0 -1474
- package/src/commands/members.ts +0 -1181
- package/src/commands/onboard-identity-guard.test.ts +0 -99
- package/src/commands/onboard-identity-guard.ts +0 -103
- package/src/commands/onboard-join.test.ts +0 -96
- package/src/commands/onboard-join.ts +0 -101
- package/src/commands/onboard-warning.test.ts +0 -26
- package/src/commands/onboard-warning.ts +0 -12
- package/src/commands/onboard.ts +0 -267
- package/src/commands/outposts-heartbeat.test.ts +0 -299
- package/src/commands/outposts-heartbeat.ts +0 -310
- package/src/commands/outposts-replica-sync.test.ts +0 -272
- package/src/commands/outposts-self-deploy.test.ts +0 -243
- package/src/commands/outposts.test.ts +0 -1039
- package/src/commands/outposts.ts +0 -1935
- package/src/commands/pack-install-secret-authorization.test.ts +0 -115
- package/src/commands/pack-install.test.ts +0 -1469
- package/src/commands/pack-install.ts +0 -2256
- package/src/commands/pack-update-cache.test.ts +0 -149
- package/src/commands/packs-update-api-key.test.ts +0 -105
- package/src/commands/packs.test.ts +0 -88
- package/src/commands/packs.ts +0 -622
- package/src/commands/people.test.ts +0 -807
- package/src/commands/people.ts +0 -422
- package/src/commands/pkg-install.dispatch.test.ts +0 -103
- package/src/commands/pkg-install.ts +0 -221
- package/src/commands/pkg-list.test.ts +0 -79
- package/src/commands/pkg-list.ts +0 -13
- package/src/commands/pkg-remove.ts +0 -71
- package/src/commands/pkg-update.ts +0 -189
- package/src/commands/publish.test.ts +0 -650
- package/src/commands/publish.ts +0 -580
- package/src/commands/reindex.test.ts +0 -259
- package/src/commands/reindex.ts +0 -274
- package/src/commands/rescue.test.ts +0 -39
- package/src/commands/rescue.ts +0 -210
- package/src/commands/run.env-local.test.ts +0 -88
- package/src/commands/run.test.ts +0 -45
- package/src/commands/run.ts +0 -190
- package/src/commands/safe-extract.test.ts +0 -459
- package/src/commands/safe-extract.ts +0 -444
- package/src/commands/secrets-scope.test.ts +0 -56
- package/src/commands/secrets-scope.ts +0 -32
- package/src/commands/secrets.parse-destination.test.ts +0 -38
- package/src/commands/secrets.test.ts +0 -2050
- package/src/commands/secrets.ts +0 -2249
- package/src/commands/signals.ts +0 -351
- package/src/commands/skill.test.ts +0 -770
- package/src/commands/skill.ts +0 -796
- package/src/commands/sources.ts +0 -362
- package/src/commands/sync-mode.test.ts +0 -366
- package/src/commands/sync-mode.ts +0 -387
- package/src/commands/sync-narrow.test.ts +0 -633
- package/src/commands/sync-narrow.ts +0 -555
- package/src/commands/sync.ts +0 -165
- package/src/commands/team-sync.ts +0 -628
- package/src/commands/update.ts +0 -71
- package/src/commands/whoami.ts +0 -83
- package/src/commands/workers.test.ts +0 -158
- package/src/commands/workers.ts +0 -301
- package/src/index.test.ts +0 -32
- package/src/index.ts +0 -20
- package/src/lib/db/control-plane.test.ts +0 -59
- package/src/lib/db/control-plane.ts +0 -113
- package/src/lib/db/local.test.ts +0 -81
- package/src/lib/db/local.ts +0 -148
- package/src/lib/db/migrate.test.ts +0 -133
- package/src/lib/db/migrate.ts +0 -137
- package/src/lib/db/paths.test.ts +0 -112
- package/src/lib/db/paths.ts +0 -128
- package/src/lib/db/remote-engine.test.ts +0 -44
- package/src/lib/db/remote-engine.ts +0 -148
- package/src/lib/db/remote-sql.test.ts +0 -32
- package/src/lib/db/remote-sql.ts +0 -62
- package/src/lib/db/sql.test.ts +0 -106
- package/src/lib/db/sql.ts +0 -192
- package/src/lib/hq-cloud-dep.smoke.test.ts +0 -75
- package/src/lib/local-tree-diff.test.ts +0 -301
- package/src/lib/local-tree-diff.ts +0 -362
- package/src/lib/narrow-hint-banner.test.ts +0 -235
- package/src/lib/narrow-hint-banner.ts +0 -212
- package/src/lib/plan-limit-nag.test.ts +0 -317
- package/src/lib/plan-limit-nag.ts +0 -264
- package/src/main.ts +0 -371
- package/src/node-preflight.test.ts +0 -60
- package/src/node-preflight.ts +0 -67
- package/src/outpost/session-heartbeat-bounds.test.ts +0 -195
- package/src/outpost/session-heartbeat-guard.test.ts +0 -105
- package/src/outpost/session-heartbeat-publisher.test.ts +0 -178
- package/src/outpost/session-heartbeat-publisher.ts +0 -186
- package/src/outpost/session-heartbeat-retain-guard.test.ts +0 -126
- package/src/outpost/session-heartbeat.test.ts +0 -459
- package/src/outpost/session-heartbeat.ts +0 -877
- package/src/packaging.test.ts +0 -109
- package/src/run/__fixtures__/discover-schemas/example.env.schema +0 -4
- package/src/run/discover-schemas.test.ts +0 -153
- package/src/run/discover-schemas.ts +0 -79
- package/src/run/hq-plugin.test.ts +0 -371
- package/src/run/hq-plugin.ts +0 -277
- package/src/run/varlock-shape.test.ts +0 -57
- package/src/schemas/hq-package.schema.json +0 -155
- package/src/sentry-before-send.test.ts +0 -359
- package/src/sentry-before-send.ts +0 -221
- package/src/sentry-epipe.test.ts +0 -37
- package/src/sentry-release.test.ts +0 -54
- package/src/sentry.test.ts +0 -24
- package/src/sentry.ts +0 -54
- package/src/strategies/link.ts +0 -62
- package/src/strategies/merge.ts +0 -142
- package/src/types.ts +0 -146
- package/src/utils/__fixtures__/scan-packages.generated-block.sh +0 -23
- package/src/utils/auth-error.test.ts +0 -40
- package/src/utils/auth-error.ts +0 -42
- package/src/utils/billing-gate.test.ts +0 -95
- package/src/utils/billing-gate.ts +0 -228
- package/src/utils/breadcrumb-buffer.ts +0 -18
- package/src/utils/cli-telemetry.test.ts +0 -153
- package/src/utils/cli-telemetry.ts +0 -61
- package/src/utils/cognito-session.machine.test.ts +0 -109
- package/src/utils/cognito-session.refresh.test.ts +0 -84
- package/src/utils/cognito-session.test.ts +0 -328
- package/src/utils/cognito-session.ts +0 -448
- package/src/utils/company-selection-error.test.ts +0 -42
- package/src/utils/company-selection-error.ts +0 -45
- package/src/utils/contribution-table.ts +0 -83
- package/src/utils/environmental-error.test.ts +0 -45
- package/src/utils/environmental-error.ts +0 -39
- package/src/utils/epipe.test.ts +0 -28
- package/src/utils/epipe.ts +0 -29
- package/src/utils/expected-cli-error.test.ts +0 -28
- package/src/utils/expected-cli-error.ts +0 -39
- package/src/utils/feedback-diagnostics.test.ts +0 -183
- package/src/utils/feedback-diagnostics.ts +0 -123
- package/src/utils/feedback-screenshots.test.ts +0 -134
- package/src/utils/feedback-screenshots.ts +0 -124
- package/src/utils/feedback-versions.test.ts +0 -98
- package/src/utils/feedback-versions.ts +0 -68
- package/src/utils/git.ts +0 -74
- package/src/utils/integrity.ts +0 -59
- package/src/utils/intercepted-process-exit.test.ts +0 -37
- package/src/utils/intercepted-process-exit.ts +0 -36
- package/src/utils/login-provider.test.ts +0 -42
- package/src/utils/login-provider.ts +0 -30
- package/src/utils/manifest.test.ts +0 -167
- package/src/utils/manifest.ts +0 -131
- package/src/utils/pack-contributions.test.ts +0 -603
- package/src/utils/pack-contributions.ts +0 -450
- package/src/utils/people.ts +0 -215
- package/src/utils/registry-client.ts +0 -204
- package/src/utils/registry.ts +0 -90
- package/src/utils/resolve-vault-credential.test.ts +0 -69
- package/src/utils/resolve-vault-credential.ts +0 -60
- package/src/utils/sandbox-runner-client.test.ts +0 -279
- package/src/utils/sandbox-runner-client.ts +0 -260
- package/src/utils/secrets-cache.ts +0 -183
- package/src/utils/sentry-identity.ts +0 -45
- package/src/utils/settle-with-timeout.test.ts +0 -21
- package/src/utils/settle-with-timeout.ts +0 -22
- package/src/utils/user-yaml-error.test.ts +0 -24
- package/src/utils/user-yaml-error.ts +0 -30
- package/src/utils/vault-api.test.ts +0 -536
- package/src/utils/vault-api.ts +0 -382
- package/src/utils/version-check.test.ts +0 -176
- package/src/utils/version-check.ts +0 -155
- package/src/utils/version-gate.test.ts +0 -1024
- package/src/utils/version-gate.ts +0 -702
- package/test/commands/db-tenant-isolation.test.ts +0 -94
- package/test/commands/db.test.ts +0 -85
- package/test/commands/signals.test.ts +0 -207
- package/test/commands/sources.test.ts +0 -231
- package/test/e2e/smoke-install-mcp.sh +0 -113
- package/test/fixtures/hq-pack-smoke-mcp/mcp/smoke-http.json +0 -1
- package/test/fixtures/hq-pack-smoke-mcp/package.yaml +0 -11
- package/test/fixtures/signals/action_item/sample.md +0 -16
- package/test/fixtures/signals/summary/sample.md +0 -12
- package/test/fixtures/sources/meetings/sample.md +0 -25
- package/test/helpers/cli-runner.ts +0 -150
- package/test/helpers/s3-list-mock.ts +0 -79
- package/test/helpers/vault-service-mock.ts +0 -295
- package/test/sources-signals/smoke.test.ts +0 -228
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -11
- package/vitest.e2e.config.ts +0 -7
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
-
import { internal } from 'varlock';
|
|
3
|
-
// Resolver is a type-only export in varlock@1.0.0's plugin-lib.js (d.ts/JS mismatch);
|
|
4
|
-
// the value is extracted at runtime from graph.registeredResolverFunctions below.
|
|
5
|
-
import type { Resolver } from 'varlock/plugin-lib';
|
|
6
|
-
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
-
let RuntimeResolver: typeof Resolver;
|
|
9
|
-
|
|
10
|
-
beforeAll(async () => {
|
|
11
|
-
// Spin up a minimal graph to access built-in resolvers registered by varlock.
|
|
12
|
-
// No schema files are needed — varlock registers built-in resolvers in afterInit.
|
|
13
|
-
await internal.loadEnvGraph({
|
|
14
|
-
entryFilePaths: [],
|
|
15
|
-
afterInit: async (graph) => {
|
|
16
|
-
const fns = (graph as any).registeredResolverFunctions as Record<string, unknown>;
|
|
17
|
-
const firstClass = Object.values(fns)[0];
|
|
18
|
-
if (firstClass == null) throw new Error('registeredResolverFunctions is empty — varlock API shape changed');
|
|
19
|
-
// Each registered class extends Resolver; its prototype chain gives us the base class.
|
|
20
|
-
RuntimeResolver = Object.getPrototypeOf(firstClass) as typeof Resolver;
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('varlock 1.0.0 API shape smoke test', () => {
|
|
26
|
-
it('internal.loadEnvGraph is a function', () => {
|
|
27
|
-
expect(typeof internal.loadEnvGraph).toBe('function');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('internal.EnvGraph is a function (class)', () => {
|
|
31
|
-
expect(typeof internal.EnvGraph).toBe('function');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('EnvGraph.prototype.registerRootDecorator exists', () => {
|
|
35
|
-
expect(typeof internal.EnvGraph.prototype.registerRootDecorator).toBe('function');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('EnvGraph.prototype.registerResolver exists', () => {
|
|
39
|
-
expect(typeof internal.EnvGraph.prototype.registerResolver).toBe('function');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('EnvGraph.prototype.registerItemDecorator exists', () => {
|
|
43
|
-
expect(typeof internal.EnvGraph.prototype.registerItemDecorator).toBe('function');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('EnvGraph.prototype.registerDataType exists', () => {
|
|
47
|
-
expect(typeof internal.EnvGraph.prototype.registerDataType).toBe('function');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('Resolver.prototype.process exists', () => {
|
|
51
|
-
expect(typeof RuntimeResolver.prototype.process).toBe('function');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('Resolver.prototype.resolve exists', () => {
|
|
55
|
-
expect(typeof RuntimeResolver.prototype.resolve).toBe('function');
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"title": "hq-package.yaml",
|
|
4
|
-
"description": "Manifest schema for HQ packages — versioned bundles of workers, commands, skills, and knowledge installable via hq install.",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"required": ["name", "type", "version", "description", "author", "exposes"],
|
|
7
|
-
"additionalProperties": false,
|
|
8
|
-
"properties": {
|
|
9
|
-
"name": {
|
|
10
|
-
"type": "string",
|
|
11
|
-
"description": "Package slug — lowercase alphanumeric with hyphens. Used as the registry identifier and install target directory name.",
|
|
12
|
-
"pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$",
|
|
13
|
-
"minLength": 1
|
|
14
|
-
},
|
|
15
|
-
"type": {
|
|
16
|
-
"type": "string",
|
|
17
|
-
"description": "Package type. Controls install target routing for all exposes entries.",
|
|
18
|
-
"enum": ["worker-pack", "command-set", "skill-bundle", "knowledge-base", "company-template"]
|
|
19
|
-
},
|
|
20
|
-
"version": {
|
|
21
|
-
"type": "string",
|
|
22
|
-
"description": "Semver version string for this release.",
|
|
23
|
-
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
|
|
24
|
-
},
|
|
25
|
-
"minHQVersion": {
|
|
26
|
-
"type": "string",
|
|
27
|
-
"description": "Minimum HQ version required to install this package. Installer aborts if installed HQ version is below this value.",
|
|
28
|
-
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"
|
|
29
|
-
},
|
|
30
|
-
"description": {
|
|
31
|
-
"type": "string",
|
|
32
|
-
"description": "Short human-readable description of what this package provides.",
|
|
33
|
-
"minLength": 1,
|
|
34
|
-
"maxLength": 500
|
|
35
|
-
},
|
|
36
|
-
"author": {
|
|
37
|
-
"type": "string",
|
|
38
|
-
"description": "Author name or organization that created and maintains this package.",
|
|
39
|
-
"minLength": 1
|
|
40
|
-
},
|
|
41
|
-
"repo": {
|
|
42
|
-
"type": "string",
|
|
43
|
-
"description": "Git repository URL for the package source. Used as offline fallback when the registry is unavailable.",
|
|
44
|
-
"pattern": "^(https?://|git@|ssh://).+"
|
|
45
|
-
},
|
|
46
|
-
"requires": {
|
|
47
|
-
"type": "object",
|
|
48
|
-
"description": "External dependencies this package needs at runtime.",
|
|
49
|
-
"additionalProperties": false,
|
|
50
|
-
"properties": {
|
|
51
|
-
"packages": {
|
|
52
|
-
"type": "array",
|
|
53
|
-
"description": "HQ package slugs this package depends on. Installed before this package.",
|
|
54
|
-
"items": {
|
|
55
|
-
"type": "string",
|
|
56
|
-
"pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$"
|
|
57
|
-
},
|
|
58
|
-
"uniqueItems": true
|
|
59
|
-
},
|
|
60
|
-
"services": {
|
|
61
|
-
"type": "array",
|
|
62
|
-
"description": "Service slugs required at runtime. Installer warns if not configured in the target HQ installation.",
|
|
63
|
-
"items": {
|
|
64
|
-
"type": "string",
|
|
65
|
-
"minLength": 1
|
|
66
|
-
},
|
|
67
|
-
"uniqueItems": true
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
"exposes": {
|
|
72
|
-
"type": "object",
|
|
73
|
-
"description": "Declares what this package installs into the HQ workspace. At least one sub-array must be non-empty.",
|
|
74
|
-
"additionalProperties": false,
|
|
75
|
-
"properties": {
|
|
76
|
-
"workers": {
|
|
77
|
-
"type": "array",
|
|
78
|
-
"description": "Paths within the tarball to worker.yaml files to install.",
|
|
79
|
-
"items": {
|
|
80
|
-
"type": "string",
|
|
81
|
-
"minLength": 1
|
|
82
|
-
},
|
|
83
|
-
"uniqueItems": true
|
|
84
|
-
},
|
|
85
|
-
"commands": {
|
|
86
|
-
"type": "array",
|
|
87
|
-
"description": "Paths within the tarball to command .md files to install.",
|
|
88
|
-
"items": {
|
|
89
|
-
"type": "string",
|
|
90
|
-
"minLength": 1
|
|
91
|
-
},
|
|
92
|
-
"uniqueItems": true
|
|
93
|
-
},
|
|
94
|
-
"skills": {
|
|
95
|
-
"type": "array",
|
|
96
|
-
"description": "Paths within the tarball to skill .md files to install.",
|
|
97
|
-
"items": {
|
|
98
|
-
"type": "string",
|
|
99
|
-
"minLength": 1
|
|
100
|
-
},
|
|
101
|
-
"uniqueItems": true
|
|
102
|
-
},
|
|
103
|
-
"knowledge": {
|
|
104
|
-
"type": "array",
|
|
105
|
-
"description": "Paths within the tarball to knowledge directories or files to install.",
|
|
106
|
-
"items": {
|
|
107
|
-
"type": "string",
|
|
108
|
-
"minLength": 1
|
|
109
|
-
},
|
|
110
|
-
"uniqueItems": true
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
"hooks": {
|
|
115
|
-
"type": "object",
|
|
116
|
-
"description": "Shell scripts run at install lifecycle events. Each value is a path within the tarball to an executable shell script.",
|
|
117
|
-
"additionalProperties": false,
|
|
118
|
-
"properties": {
|
|
119
|
-
"on-install": {
|
|
120
|
-
"type": "string",
|
|
121
|
-
"description": "Path to shell script run after all files are installed.",
|
|
122
|
-
"minLength": 1
|
|
123
|
-
},
|
|
124
|
-
"on-update": {
|
|
125
|
-
"type": "string",
|
|
126
|
-
"description": "Path to shell script run after an existing installation is updated.",
|
|
127
|
-
"minLength": 1
|
|
128
|
-
},
|
|
129
|
-
"on-remove": {
|
|
130
|
-
"type": "string",
|
|
131
|
-
"description": "Path to shell script run before files are removed from the HQ workspace.",
|
|
132
|
-
"minLength": 1
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
"initialization": {
|
|
137
|
-
"type": "object",
|
|
138
|
-
"description": "Optional post-install onboarding. `entrypoint` is the pack's primary get-started action (a skill or command that must resolve to one of this package's exposes.skills / exposes.commands entries); HQ surfaces a safe auto-generated 'get started' line from it after install. `prompt` is optional free-text the user can copy/paste into their agent to begin setup — treated as UNTRUSTED instruction text, surfaced only after marketplace injection-scan/moderation (suppressed for non-marketplace installs).",
|
|
139
|
-
"additionalProperties": false,
|
|
140
|
-
"properties": {
|
|
141
|
-
"entrypoint": {
|
|
142
|
-
"type": "string",
|
|
143
|
-
"minLength": 1,
|
|
144
|
-
"description": "Primary get-started action — a skill or command name (with or without a leading slash) that must resolve to a declared exposes.skills / exposes.commands entry."
|
|
145
|
-
},
|
|
146
|
-
"prompt": {
|
|
147
|
-
"type": "string",
|
|
148
|
-
"maxLength": 2000,
|
|
149
|
-
"description": "Optional copy/paste setup prompt. Untrusted; surfaced only after moderation for marketplace packs, suppressed for local/git installs."
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
"required": ["entrypoint"]
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
// src/sentry-before-send.test.ts — canonical fleet Vitest suite.
|
|
2
|
-
// This file is byte-identical across every consumer repo (no per-repo
|
|
3
|
-
// line-1 variation, unlike sentry-before-send.ts). The body-identity
|
|
4
|
-
// gate each consumer runs is `diff hq-console/src/sentry-before-send.test.ts
|
|
5
|
-
// <consumer>/src/sentry-before-send.test.ts` returns empty (no tail -n +2).
|
|
6
|
-
import { describe, expect, it } from "vitest";
|
|
7
|
-
import type { ErrorEvent, EventHint } from "@sentry/nextjs";
|
|
8
|
-
import { beforeSend } from "./sentry-before-send";
|
|
9
|
-
|
|
10
|
-
const REDACTED = "[Filtered]";
|
|
11
|
-
|
|
12
|
-
function run(event: ErrorEvent): ErrorEvent {
|
|
13
|
-
const result = beforeSend(event, {} as EventHint);
|
|
14
|
-
if (!result) throw new Error("beforeSend dropped event unexpectedly");
|
|
15
|
-
return result;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe("scrubHeaders — SENSITIVE_HEADER_NAMES case-insensitive redaction", () => {
|
|
19
|
-
const sensitiveHeaders = [
|
|
20
|
-
"authorization",
|
|
21
|
-
"proxy-authorization",
|
|
22
|
-
"cookie",
|
|
23
|
-
"set-cookie",
|
|
24
|
-
"x-api-key",
|
|
25
|
-
"x-auth-token",
|
|
26
|
-
"x-access-token",
|
|
27
|
-
"x-session-token",
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
it.each(sensitiveHeaders)("redacts %s header (and case variants)", (name) => {
|
|
31
|
-
const upper = name.toUpperCase();
|
|
32
|
-
const out = run({
|
|
33
|
-
request: {
|
|
34
|
-
headers: { [upper]: "leaky-value", "x-trace-id": "keep-me" },
|
|
35
|
-
},
|
|
36
|
-
} as unknown as ErrorEvent);
|
|
37
|
-
expect((out.request!.headers as Record<string, unknown>)[upper]).toBe(REDACTED);
|
|
38
|
-
expect((out.request!.headers as Record<string, unknown>)["x-trace-id"]).toBe("keep-me");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("redacts a raw Cookie header that lands on request.headers.cookie", () => {
|
|
42
|
-
const out = run({
|
|
43
|
-
request: {
|
|
44
|
-
headers: {
|
|
45
|
-
Cookie: "authjs.session-token=abc; other=keep",
|
|
46
|
-
"x-trace-id": "keep-me",
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
} as unknown as ErrorEvent);
|
|
50
|
-
expect((out.request!.headers as Record<string, unknown>).Cookie).toBe(REDACTED);
|
|
51
|
-
expect((out.request!.headers as Record<string, unknown>)["x-trace-id"]).toBe("keep-me");
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe("scrubCookies — SENSITIVE_COOKIE_NAMES (Auth.js v5 + v4 legacy + Clerk) + raw-string fallback", () => {
|
|
56
|
-
// v5 (Auth.js): session / callback-url use __Secure-; csrf-token uses
|
|
57
|
-
// __Host- (NOT __Secure-). OAuth-state families (pkce / state / nonce /
|
|
58
|
-
// challenge) each pair bare + __Secure-.
|
|
59
|
-
const v5Names = [
|
|
60
|
-
"authjs.session-token",
|
|
61
|
-
"__secure-authjs.session-token",
|
|
62
|
-
"authjs.csrf-token",
|
|
63
|
-
"__host-authjs.csrf-token",
|
|
64
|
-
"authjs.callback-url",
|
|
65
|
-
"__secure-authjs.callback-url",
|
|
66
|
-
"authjs.pkce.code_verifier",
|
|
67
|
-
"__secure-authjs.pkce.code_verifier",
|
|
68
|
-
"authjs.state",
|
|
69
|
-
"__secure-authjs.state",
|
|
70
|
-
"authjs.nonce",
|
|
71
|
-
"__secure-authjs.nonce",
|
|
72
|
-
"authjs.challenge",
|
|
73
|
-
"__secure-authjs.challenge",
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
// v4 (NextAuth legacy): same prefix discipline — csrf uses __Host-, others
|
|
77
|
-
// use __Secure-. Kept in the set so accidental downgrades / mixed-version
|
|
78
|
-
// monorepos don't silently leak.
|
|
79
|
-
const v4Names = [
|
|
80
|
-
"next-auth.session-token",
|
|
81
|
-
"__secure-next-auth.session-token",
|
|
82
|
-
"next-auth.csrf-token",
|
|
83
|
-
"__host-next-auth.csrf-token",
|
|
84
|
-
"next-auth.callback-url",
|
|
85
|
-
"__secure-next-auth.callback-url",
|
|
86
|
-
"next-auth.pkce.code_verifier",
|
|
87
|
-
"__secure-next-auth.pkce.code_verifier",
|
|
88
|
-
"next-auth.state",
|
|
89
|
-
"__secure-next-auth.state",
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
const clerkNames = ["__clerk_db_jwt", "__session"];
|
|
93
|
-
|
|
94
|
-
it.each([...v5Names, ...v4Names, ...clerkNames])(
|
|
95
|
-
"redacts cookie %s (case-insensitive)",
|
|
96
|
-
(name) => {
|
|
97
|
-
const out = run({
|
|
98
|
-
request: {
|
|
99
|
-
cookies: { [name.toUpperCase()]: "secret-session-value", keep_me: "ok" },
|
|
100
|
-
},
|
|
101
|
-
} as unknown as ErrorEvent);
|
|
102
|
-
const cookies = out.request!.cookies as Record<string, unknown>;
|
|
103
|
-
expect(cookies[name.toUpperCase()]).toBe(REDACTED);
|
|
104
|
-
expect(cookies.keep_me).toBe("ok");
|
|
105
|
-
},
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
it("does NOT include a __Secure-authjs.csrf-token assertion — Auth.js v5 never emits that name (uses __Host- instead)", () => {
|
|
109
|
-
// This test is a read-through spec comment: the set MUST NOT have an
|
|
110
|
-
// entry for __Secure-authjs.csrf-token. If a maintainer ever adds one
|
|
111
|
-
// mechanically-by-pattern, this test documents why it is wrong.
|
|
112
|
-
const out = run({
|
|
113
|
-
request: {
|
|
114
|
-
cookies: { "__Secure-authjs.csrf-token": "does-not-exist-in-prod" },
|
|
115
|
-
},
|
|
116
|
-
} as unknown as ErrorEvent);
|
|
117
|
-
// The value is NOT redacted because the set does not contain that name.
|
|
118
|
-
// This is deliberate — see SENSITIVE_COOKIE_NAMES comment in the module.
|
|
119
|
-
const cookies = out.request!.cookies as Record<string, unknown>;
|
|
120
|
-
expect(cookies["__Secure-authjs.csrf-token"]).toBe("does-not-exist-in-prod");
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("wholesale-redacts a raw-string Cookie header", () => {
|
|
124
|
-
const out = run({
|
|
125
|
-
request: { cookies: "anything=here; other=keep" },
|
|
126
|
-
} as unknown as ErrorEvent);
|
|
127
|
-
expect(out.request!.cookies).toBe(REDACTED);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it("leaves undefined cookies alone", () => {
|
|
131
|
-
const out = run({ request: { headers: {} } } as unknown as ErrorEvent);
|
|
132
|
-
expect(out.request!.cookies).toBeUndefined();
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
describe("scrubFields — recursive redaction with case-insensitivity, arrays, nested, cycles", () => {
|
|
137
|
-
it("redacts top-level sensitive field names case-insensitively", () => {
|
|
138
|
-
const out = run({
|
|
139
|
-
extra: {
|
|
140
|
-
token: "abc",
|
|
141
|
-
Password: "pw",
|
|
142
|
-
APIKEY: "k",
|
|
143
|
-
api_key: "k2",
|
|
144
|
-
IdToken: "id",
|
|
145
|
-
ACCESSTOKEN: "at",
|
|
146
|
-
RefreshToken: "rt",
|
|
147
|
-
keep: "yes",
|
|
148
|
-
},
|
|
149
|
-
} as unknown as ErrorEvent);
|
|
150
|
-
const extra = out.extra as Record<string, unknown>;
|
|
151
|
-
expect(extra.token).toBe(REDACTED);
|
|
152
|
-
expect(extra.Password).toBe(REDACTED);
|
|
153
|
-
expect(extra.APIKEY).toBe(REDACTED);
|
|
154
|
-
expect(extra.api_key).toBe(REDACTED);
|
|
155
|
-
expect(extra.IdToken).toBe(REDACTED);
|
|
156
|
-
expect(extra.ACCESSTOKEN).toBe(REDACTED);
|
|
157
|
-
expect(extra.RefreshToken).toBe(REDACTED);
|
|
158
|
-
expect(extra.keep).toBe("yes");
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("recurses into nested objects and arrays", () => {
|
|
162
|
-
const out = run({
|
|
163
|
-
extra: {
|
|
164
|
-
nested: { deeper: { token: "t", safe: 1 } },
|
|
165
|
-
items: [{ password: "pw" }, { other: "ok" }],
|
|
166
|
-
},
|
|
167
|
-
} as unknown as ErrorEvent);
|
|
168
|
-
const extra = out.extra as Record<string, any>;
|
|
169
|
-
expect(extra.nested.deeper.token).toBe(REDACTED);
|
|
170
|
-
expect(extra.nested.deeper.safe).toBe(1);
|
|
171
|
-
expect(extra.items[0].password).toBe(REDACTED);
|
|
172
|
-
expect(extra.items[1].other).toBe("ok");
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it("handles circular references without stack overflow and scrubs fields reachable only through the cycle", () => {
|
|
176
|
-
const cyclic: Record<string, unknown> = { token: "leak" };
|
|
177
|
-
cyclic.self = cyclic;
|
|
178
|
-
const out = run({ extra: { outer: cyclic } } as unknown as ErrorEvent);
|
|
179
|
-
const outer = (out.extra as any).outer;
|
|
180
|
-
// Top-level field is scrubbed.
|
|
181
|
-
expect(outer.token).toBe(REDACTED);
|
|
182
|
-
// The Map<original, scrubbed> cycle fix means re-visits return the
|
|
183
|
-
// memoized scrubbed copy, not the un-scrubbed original — so
|
|
184
|
-
// `outer.self.token` is ALSO [Filtered], not the leaked value.
|
|
185
|
-
expect(outer.self.token).toBe(REDACTED);
|
|
186
|
-
expect(outer.self).toBe(outer);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
it("scalar-string defense-in-depth: redacts embedded credentials in extra.note even when the key is NOT in SENSITIVE_FIELD_NAMES", () => {
|
|
190
|
-
const out = run({
|
|
191
|
-
extra: { note: "Something broke, password=hunter2 failed" },
|
|
192
|
-
} as unknown as ErrorEvent);
|
|
193
|
-
const extra = out.extra as Record<string, unknown>;
|
|
194
|
-
expect(extra.note).toContain(`password=${REDACTED}`);
|
|
195
|
-
expect(extra.note).not.toContain("hunter2");
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("scalar-string defense-in-depth: redacts a Bearer in user.bio (key NOT in SENSITIVE_FIELD_NAMES)", () => {
|
|
199
|
-
const out = run({
|
|
200
|
-
user: { id: "u1", email: "a@b.c", bio: "authorization: Bearer leak" },
|
|
201
|
-
} as unknown as ErrorEvent);
|
|
202
|
-
const user = out.user as Record<string, unknown>;
|
|
203
|
-
expect(user.id).toBe("u1");
|
|
204
|
-
expect(user.email).toBe("a@b.c");
|
|
205
|
-
expect(user.bio).toContain(`Bearer ${REDACTED}`);
|
|
206
|
-
expect(user.bio).not.toContain("leak");
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
describe("scrubString — regex passes for kv, scheme+credential, JWT triplets", () => {
|
|
211
|
-
it("redacts key=value and key: value pairs", () => {
|
|
212
|
-
const out = run({
|
|
213
|
-
message: "password=hunter2 and api-key: abc123 should be redacted",
|
|
214
|
-
} as unknown as ErrorEvent);
|
|
215
|
-
expect(out.message).toContain(`password=${REDACTED}`);
|
|
216
|
-
expect(out.message).toContain(`api-key:${REDACTED}`);
|
|
217
|
-
expect(out.message).not.toContain("hunter2");
|
|
218
|
-
expect(out.message).not.toContain("abc123");
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("redacts Bearer / Basic credentials", () => {
|
|
222
|
-
const out = run({
|
|
223
|
-
message: "Got header Bearer abcDEF._~+/=- and Basic Zm9vOmJhcg==",
|
|
224
|
-
} as unknown as ErrorEvent);
|
|
225
|
-
expect(out.message).toContain(`Bearer ${REDACTED}`);
|
|
226
|
-
expect(out.message).toContain(`Basic ${REDACTED}`);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it("redacts non-JWT-shaped accessToken/refreshToken/id_token values in free text", () => {
|
|
230
|
-
const out = run({
|
|
231
|
-
message:
|
|
232
|
-
"refreshToken=opaqueBase64NotAJwt-xyz and accessToken: anotherOpaqueValue and id_token=short",
|
|
233
|
-
} as unknown as ErrorEvent);
|
|
234
|
-
expect(out.message).toContain(`refreshToken=${REDACTED}`);
|
|
235
|
-
expect(out.message).toContain(`accessToken:${REDACTED}`);
|
|
236
|
-
expect(out.message).toContain(`id_token=${REDACTED}`);
|
|
237
|
-
expect(out.message).not.toContain("opaqueBase64NotAJwt-xyz");
|
|
238
|
-
expect(out.message).not.toContain("anotherOpaqueValue");
|
|
239
|
-
expect(out.message).not.toContain("=short");
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
it("redacts bare JWT triplets", () => {
|
|
243
|
-
const jwt = "eyJhbGciOi12345.eyJzdWIiOi67890.sig_abcdef1234";
|
|
244
|
-
const out = run({ message: `token was ${jwt} yeah` } as unknown as ErrorEvent);
|
|
245
|
-
expect(out.message).not.toContain(jwt);
|
|
246
|
-
expect(out.message).toContain(REDACTED);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
describe("scrubQueryString — parse + fallback", () => {
|
|
251
|
-
it("parses well-formed query strings with a leading ? and redacts sensitive keys", () => {
|
|
252
|
-
const out = run({
|
|
253
|
-
request: {
|
|
254
|
-
query_string: "?foo=bar&token=leak&password=pw&keep=me",
|
|
255
|
-
},
|
|
256
|
-
} as unknown as ErrorEvent);
|
|
257
|
-
const qs = out.request!.query_string as string;
|
|
258
|
-
expect(qs.startsWith("?")).toBe(true);
|
|
259
|
-
expect(qs).toContain("foo=bar");
|
|
260
|
-
expect(qs).toContain(`token=${REDACTED}`);
|
|
261
|
-
expect(qs).toContain(`password=${REDACTED}`);
|
|
262
|
-
expect(qs).toContain("keep=me");
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it("parses no-leading-? strings as well", () => {
|
|
266
|
-
const out = run({
|
|
267
|
-
request: { query_string: "token=leak&keep=1" },
|
|
268
|
-
} as unknown as ErrorEvent);
|
|
269
|
-
const qs = out.request!.query_string as string;
|
|
270
|
-
expect(qs.startsWith("?")).toBe(false);
|
|
271
|
-
expect(qs).toContain(`token=${REDACTED}`);
|
|
272
|
-
expect(qs).toContain("keep=1");
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it("leaves non-string query_string alone", () => {
|
|
276
|
-
const out = run({
|
|
277
|
-
request: { query_string: undefined },
|
|
278
|
-
} as unknown as ErrorEvent);
|
|
279
|
-
expect(out.request!.query_string).toBeUndefined();
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
describe("event-level walk — exception.values, message, breadcrumbs, user, extra, contexts, request.data", () => {
|
|
284
|
-
it("scrubs exception.values[].value strings", () => {
|
|
285
|
-
const out = run({
|
|
286
|
-
exception: {
|
|
287
|
-
values: [
|
|
288
|
-
{ type: "Error", value: "password=sekret failed" },
|
|
289
|
-
{ type: "Error", value: "clean" },
|
|
290
|
-
],
|
|
291
|
-
},
|
|
292
|
-
} as unknown as ErrorEvent);
|
|
293
|
-
expect(out.exception!.values![0].value).toContain(`password=${REDACTED}`);
|
|
294
|
-
expect(out.exception!.values![0].value).not.toContain("sekret");
|
|
295
|
-
expect(out.exception!.values![1].value).toBe("clean");
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
it("scrubs event.message", () => {
|
|
299
|
-
const out = run({ message: "Bearer leaked.jwt.token" } as unknown as ErrorEvent);
|
|
300
|
-
expect(out.message).toContain(`Bearer ${REDACTED}`);
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
it("scrubs breadcrumbs.message (string) and breadcrumbs.data (structured)", () => {
|
|
304
|
-
const out = run({
|
|
305
|
-
breadcrumbs: [
|
|
306
|
-
{
|
|
307
|
-
category: "fetch",
|
|
308
|
-
message: "GET /api?token=abc",
|
|
309
|
-
data: { url: "/api", password: "leak" },
|
|
310
|
-
},
|
|
311
|
-
],
|
|
312
|
-
} as unknown as ErrorEvent);
|
|
313
|
-
const bc = out.breadcrumbs![0];
|
|
314
|
-
expect(bc.message).toContain(`token=${REDACTED}`);
|
|
315
|
-
expect((bc.data as Record<string, unknown>).password).toBe(REDACTED);
|
|
316
|
-
expect((bc.data as Record<string, unknown>).url).toBe("/api");
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
it("scrubs event.user fields", () => {
|
|
320
|
-
const out = run({
|
|
321
|
-
user: { id: "u1", email: "a@b.c", token: "bad", IdToken: "cognito" },
|
|
322
|
-
} as unknown as ErrorEvent);
|
|
323
|
-
const user = out.user as Record<string, unknown>;
|
|
324
|
-
expect(user.id).toBe("u1");
|
|
325
|
-
expect(user.email).toBe("a@b.c");
|
|
326
|
-
expect(user.token).toBe(REDACTED);
|
|
327
|
-
expect(user.IdToken).toBe(REDACTED);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it("scrubs event.extra", () => {
|
|
331
|
-
const out = run({ extra: { password: "x", safe: "y" } } as unknown as ErrorEvent);
|
|
332
|
-
expect((out.extra as Record<string, unknown>).password).toBe(REDACTED);
|
|
333
|
-
expect((out.extra as Record<string, unknown>).safe).toBe("y");
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it("scrubs event.contexts", () => {
|
|
337
|
-
const out = run({
|
|
338
|
-
contexts: {
|
|
339
|
-
auth: { token: "x", scheme: "bearer" },
|
|
340
|
-
runtime: { name: "node", version: "22" },
|
|
341
|
-
},
|
|
342
|
-
} as unknown as ErrorEvent);
|
|
343
|
-
const auth = (out.contexts as any).auth;
|
|
344
|
-
const runtime = (out.contexts as any).runtime;
|
|
345
|
-
expect(auth.token).toBe(REDACTED);
|
|
346
|
-
expect(auth.scheme).toBe("bearer");
|
|
347
|
-
expect(runtime.name).toBe("node");
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("scrubs structured request body via request.data", () => {
|
|
351
|
-
const out = run({
|
|
352
|
-
request: { data: { username: "u", password: "pw", nested: { token: "t" } } },
|
|
353
|
-
} as unknown as ErrorEvent);
|
|
354
|
-
const data = out.request!.data as Record<string, any>;
|
|
355
|
-
expect(data.username).toBe("u");
|
|
356
|
-
expect(data.password).toBe(REDACTED);
|
|
357
|
-
expect(data.nested.token).toBe(REDACTED);
|
|
358
|
-
});
|
|
359
|
-
});
|