@indigoai-us/hq-cli 5.77.13 → 5.78.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 +34 -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/members.js +16 -5
- package/dist/commands/pack-install.d.ts +14 -0
- package/dist/commands/pack-install.js +51 -2
- package/dist/commands/pkg-install.js +43 -0
- package/dist/commands/run.js +8 -0
- package/dist/commands/secrets.js +125 -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 -2247
- package/src/commands/pack-update-cache.test.ts +0 -149
- 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 -71
- package/src/commands/pkg-install.ts +0 -215
- 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 -184
- 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 -2037
- package/src/commands/secrets.ts +0 -2240
- 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,153 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
// Each case does vi.resetModules() + a dynamic import() to reset the module-scoped
|
|
4
|
-
// once-per-process memoization; the cold transform/import is slow, so raise the
|
|
5
|
-
// per-test timeout well above the default 5s.
|
|
6
|
-
vi.setConfig({ testTimeout: 30_000 });
|
|
7
|
-
|
|
8
|
-
const mocks = vi.hoisted(() => ({
|
|
9
|
-
browserLogin: vi.fn(),
|
|
10
|
-
isExpiring: vi.fn(),
|
|
11
|
-
isMachineIdentity: vi.fn(),
|
|
12
|
-
loadCachedTokens: vi.fn(),
|
|
13
|
-
refreshTokens: vi.fn(),
|
|
14
|
-
vaultApiFetch: vi.fn(),
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
vi.mock("@indigoai-us/hq-cloud", async (importOriginal) => {
|
|
18
|
-
const actual = await importOriginal<typeof import("@indigoai-us/hq-cloud")>();
|
|
19
|
-
return { ...actual, ...mocks };
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
vi.mock("./vault-api.js", () => ({
|
|
23
|
-
vaultApiFetch: mocks.vaultApiFetch,
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
vi.mock("../cli-version.js", () => ({
|
|
27
|
-
CLI_NAME: "@indigoai-us/hq-cli",
|
|
28
|
-
CLI_VERSION: "5.68.1",
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
const HUMAN_TOKENS = {
|
|
32
|
-
accessToken: "human-access-token",
|
|
33
|
-
idToken: "human-id-token",
|
|
34
|
-
refreshToken: "human-refresh-token",
|
|
35
|
-
expiresAt: Date.now() + 3_600_000,
|
|
36
|
-
tokenType: "Bearer" as const,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const MACHINE_TOKENS = {
|
|
40
|
-
...HUMAN_TOKENS,
|
|
41
|
-
accessToken: "machine-access-token",
|
|
42
|
-
idToken: "machine-id-token",
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
async function loadEmitter() {
|
|
46
|
-
vi.resetModules();
|
|
47
|
-
return import("./cli-telemetry.js");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
beforeEach(() => {
|
|
51
|
-
vi.resetAllMocks();
|
|
52
|
-
mocks.isMachineIdentity.mockReturnValue(false);
|
|
53
|
-
mocks.isExpiring.mockReturnValue(false);
|
|
54
|
-
mocks.vaultApiFetch.mockResolvedValue(new Response(null, { status: 202 }));
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
afterEach(() => {
|
|
58
|
-
vi.useRealTimers();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("emitCliSessionStarted", () => {
|
|
62
|
-
it("posts the privacy-safe event with a valid cached human token", async () => {
|
|
63
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
64
|
-
const { emitCliSessionStarted } = await loadEmitter();
|
|
65
|
-
|
|
66
|
-
await emitCliSessionStarted();
|
|
67
|
-
|
|
68
|
-
expect(mocks.vaultApiFetch).toHaveBeenCalledTimes(1);
|
|
69
|
-
const request = mocks.vaultApiFetch.mock.calls[0]?.[0];
|
|
70
|
-
expect(request).toMatchObject({
|
|
71
|
-
token: HUMAN_TOKENS.accessToken,
|
|
72
|
-
path: "/v1/telemetry/events",
|
|
73
|
-
method: "POST",
|
|
74
|
-
signal: expect.any(AbortSignal),
|
|
75
|
-
});
|
|
76
|
-
expect(request.body.events).toHaveLength(1);
|
|
77
|
-
expect(request.body.events[0]).toEqual({
|
|
78
|
-
eventName: "cli_session_started",
|
|
79
|
-
app: "hq-cli",
|
|
80
|
-
source: "cli",
|
|
81
|
-
occurredAt: expect.any(String),
|
|
82
|
-
schemaVersion: 1,
|
|
83
|
-
properties: { version: "5.68.1" },
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("uses the cached ID token for a machine identity", async () => {
|
|
88
|
-
mocks.isMachineIdentity.mockReturnValue(true);
|
|
89
|
-
mocks.loadCachedTokens.mockReturnValue(MACHINE_TOKENS);
|
|
90
|
-
const { emitCliSessionStarted } = await loadEmitter();
|
|
91
|
-
|
|
92
|
-
await emitCliSessionStarted();
|
|
93
|
-
|
|
94
|
-
expect(mocks.vaultApiFetch).toHaveBeenCalledWith(
|
|
95
|
-
expect.objectContaining({ token: MACHINE_TOKENS.idToken }),
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it.each([
|
|
100
|
-
["is absent", null, false],
|
|
101
|
-
["is expiring", HUMAN_TOKENS, true],
|
|
102
|
-
])(
|
|
103
|
-
"does not emit or refresh/login when the cached token %s",
|
|
104
|
-
async (_description, cachedTokens, expiring) => {
|
|
105
|
-
mocks.loadCachedTokens.mockReturnValue(cachedTokens);
|
|
106
|
-
mocks.isExpiring.mockReturnValue(expiring);
|
|
107
|
-
const { emitCliSessionStarted } = await loadEmitter();
|
|
108
|
-
|
|
109
|
-
await emitCliSessionStarted();
|
|
110
|
-
|
|
111
|
-
expect(mocks.vaultApiFetch).not.toHaveBeenCalled();
|
|
112
|
-
expect(mocks.refreshTokens).not.toHaveBeenCalled();
|
|
113
|
-
expect(mocks.browserLogin).not.toHaveBeenCalled();
|
|
114
|
-
},
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
it("swallows a non-2xx telemetry response", async () => {
|
|
118
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
119
|
-
mocks.vaultApiFetch.mockResolvedValue(new Response(null, { status: 503 }));
|
|
120
|
-
const { emitCliSessionStarted } = await loadEmitter();
|
|
121
|
-
|
|
122
|
-
await expect(emitCliSessionStarted()).resolves.toBeUndefined();
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it("aborts a slow telemetry request without failing the command", async () => {
|
|
126
|
-
vi.useFakeTimers();
|
|
127
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
128
|
-
mocks.vaultApiFetch.mockImplementation(
|
|
129
|
-
({ signal }: { signal: AbortSignal }) =>
|
|
130
|
-
new Promise((_resolve, reject) => {
|
|
131
|
-
signal.addEventListener("abort", () => reject(new Error("aborted")), {
|
|
132
|
-
once: true,
|
|
133
|
-
});
|
|
134
|
-
}),
|
|
135
|
-
);
|
|
136
|
-
const { emitCliSessionStarted } = await loadEmitter();
|
|
137
|
-
|
|
138
|
-
const emission = emitCliSessionStarted();
|
|
139
|
-
await vi.advanceTimersByTimeAsync(1_200);
|
|
140
|
-
|
|
141
|
-
await expect(emission).resolves.toBeUndefined();
|
|
142
|
-
expect(mocks.vaultApiFetch.mock.calls[0]?.[0].signal.aborted).toBe(true);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it("posts at most once when the root hook is invoked repeatedly", async () => {
|
|
146
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
147
|
-
const { emitCliSessionStarted } = await loadEmitter();
|
|
148
|
-
|
|
149
|
-
await Promise.all([emitCliSessionStarted(), emitCliSessionStarted()]);
|
|
150
|
-
|
|
151
|
-
expect(mocks.vaultApiFetch).toHaveBeenCalledTimes(1);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { CLI_VERSION } from "../cli-version.js";
|
|
2
|
-
import {
|
|
3
|
-
isExpiring,
|
|
4
|
-
isMachineIdentity,
|
|
5
|
-
loadCachedTokens,
|
|
6
|
-
} from "./cognito-session.js";
|
|
7
|
-
import { vaultApiFetch } from "./vault-api.js";
|
|
8
|
-
|
|
9
|
-
const TELEMETRY_TIMEOUT_MS = 1_200;
|
|
10
|
-
|
|
11
|
-
let cliSessionStartedPromise: Promise<void> | undefined;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Emit the authenticated CLI session signal using an already-cached token.
|
|
15
|
-
* This deliberately never refreshes a session or opens a browser.
|
|
16
|
-
*/
|
|
17
|
-
export function emitCliSessionStarted(): Promise<void> {
|
|
18
|
-
cliSessionStartedPromise ??= emitCachedCliSessionStarted();
|
|
19
|
-
return cliSessionStartedPromise;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async function emitCachedCliSessionStarted(): Promise<void> {
|
|
23
|
-
try {
|
|
24
|
-
const cached = loadCachedTokens();
|
|
25
|
-
if (!cached || isExpiring(cached, 120)) return;
|
|
26
|
-
|
|
27
|
-
const token = isMachineIdentity() ? cached.idToken : cached.accessToken;
|
|
28
|
-
if (!token) return;
|
|
29
|
-
|
|
30
|
-
const controller = new AbortController();
|
|
31
|
-
const timeout = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const response = await vaultApiFetch({
|
|
35
|
-
token,
|
|
36
|
-
path: "/v1/telemetry/events",
|
|
37
|
-
method: "POST",
|
|
38
|
-
body: {
|
|
39
|
-
events: [
|
|
40
|
-
{
|
|
41
|
-
eventName: "cli_session_started",
|
|
42
|
-
app: "hq-cli",
|
|
43
|
-
source: "cli",
|
|
44
|
-
occurredAt: new Date().toISOString(),
|
|
45
|
-
schemaVersion: 1,
|
|
46
|
-
properties: { version: CLI_VERSION },
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
signal: controller.signal,
|
|
51
|
-
});
|
|
52
|
-
if (!response.ok) return;
|
|
53
|
-
} catch {
|
|
54
|
-
// Telemetry is best effort and must never affect a CLI command.
|
|
55
|
-
} finally {
|
|
56
|
-
clearTimeout(timeout);
|
|
57
|
-
}
|
|
58
|
-
} catch {
|
|
59
|
-
// Cached-token reads are also best effort (for example, a malformed cache).
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Machine-identity behavior of the shared Cognito session helpers.
|
|
3
|
-
*
|
|
4
|
-
* When machine creds are present (company agent boxes), the CLI must:
|
|
5
|
-
* - return the ID token from ensureCognitoToken() — the vault API's JWT
|
|
6
|
-
* authorizer accepts ID tokens and the agent claims
|
|
7
|
-
* (custom:entityType/custom:entityUid) ride the ID token only
|
|
8
|
-
* - never refresh or open a browser — sessions re-mint on demand
|
|
9
|
-
* - treat `hq auth refresh` as a non-interactive ensure-valid-session call
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
13
|
-
|
|
14
|
-
const mocks = vi.hoisted(() => ({
|
|
15
|
-
isMachineIdentity: vi.fn(),
|
|
16
|
-
getValidMachineTokens: vi.fn(),
|
|
17
|
-
mintMachineTokens: vi.fn(),
|
|
18
|
-
loadCachedTokens: vi.fn(),
|
|
19
|
-
refreshTokens: vi.fn(),
|
|
20
|
-
browserLogin: vi.fn(),
|
|
21
|
-
isExpiring: vi.fn(),
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
|
-
vi.mock("@indigoai-us/hq-cloud", async (importOriginal) => {
|
|
25
|
-
const actual = await importOriginal<typeof import("@indigoai-us/hq-cloud")>();
|
|
26
|
-
return { ...actual, ...mocks };
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
import {
|
|
30
|
-
ensureCognitoToken,
|
|
31
|
-
refreshCachedSession,
|
|
32
|
-
} from "./cognito-session.js";
|
|
33
|
-
|
|
34
|
-
const MACHINE_TOKENS = {
|
|
35
|
-
accessToken: "machine-access-token",
|
|
36
|
-
idToken: "machine-id-token",
|
|
37
|
-
refreshToken: "",
|
|
38
|
-
expiresAt: Date.now() + 3600_000,
|
|
39
|
-
tokenType: "Bearer" as const,
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
beforeEach(() => {
|
|
43
|
-
vi.resetAllMocks();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe("ensureCognitoToken in machine mode", () => {
|
|
47
|
-
it("returns the ID token (agent claims ride the ID token only)", async () => {
|
|
48
|
-
mocks.isMachineIdentity.mockReturnValue(true);
|
|
49
|
-
mocks.getValidMachineTokens.mockResolvedValue(MACHINE_TOKENS);
|
|
50
|
-
|
|
51
|
-
const token = await ensureCognitoToken({ interactive: false });
|
|
52
|
-
|
|
53
|
-
expect(token).toBe("machine-id-token");
|
|
54
|
-
expect(mocks.getValidMachineTokens).toHaveBeenCalledTimes(1);
|
|
55
|
-
expect(mocks.refreshTokens).not.toHaveBeenCalled();
|
|
56
|
-
expect(mocks.browserLogin).not.toHaveBeenCalled();
|
|
57
|
-
expect(mocks.loadCachedTokens).not.toHaveBeenCalled();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("falls through to the browser-session path for human identities", async () => {
|
|
61
|
-
mocks.isMachineIdentity.mockReturnValue(false);
|
|
62
|
-
mocks.loadCachedTokens.mockReturnValue({
|
|
63
|
-
...MACHINE_TOKENS,
|
|
64
|
-
accessToken: "human-access-token",
|
|
65
|
-
});
|
|
66
|
-
mocks.isExpiring.mockReturnValue(false);
|
|
67
|
-
|
|
68
|
-
const token = await ensureCognitoToken({ interactive: false });
|
|
69
|
-
|
|
70
|
-
expect(token).toBe("human-access-token");
|
|
71
|
-
expect(mocks.getValidMachineTokens).not.toHaveBeenCalled();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("propagates mint failures instead of opening a browser", async () => {
|
|
75
|
-
mocks.isMachineIdentity.mockReturnValue(true);
|
|
76
|
-
mocks.getValidMachineTokens.mockRejectedValue(new Error("mint failed"));
|
|
77
|
-
|
|
78
|
-
await expect(ensureCognitoToken()).rejects.toThrow("mint failed");
|
|
79
|
-
expect(mocks.browserLogin).not.toHaveBeenCalled();
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe("refreshCachedSession in machine mode", () => {
|
|
84
|
-
it("ensures a healthy machine session via getValidMachineTokens", async () => {
|
|
85
|
-
mocks.isMachineIdentity.mockReturnValue(true);
|
|
86
|
-
mocks.getValidMachineTokens.mockResolvedValue(MACHINE_TOKENS);
|
|
87
|
-
|
|
88
|
-
const result = await refreshCachedSession();
|
|
89
|
-
|
|
90
|
-
expect(result).toEqual({ refreshed: true });
|
|
91
|
-
expect(mocks.getValidMachineTokens).toHaveBeenCalledTimes(1);
|
|
92
|
-
expect(mocks.mintMachineTokens).not.toHaveBeenCalled();
|
|
93
|
-
expect(mocks.refreshTokens).not.toHaveBeenCalled();
|
|
94
|
-
expect(mocks.browserLogin).not.toHaveBeenCalled();
|
|
95
|
-
expect(mocks.loadCachedTokens).not.toHaveBeenCalled();
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("surfaces the machine-session error as the reason on failure", async () => {
|
|
99
|
-
mocks.isMachineIdentity.mockReturnValue(true);
|
|
100
|
-
mocks.getValidMachineTokens.mockRejectedValue(new Error("NotAuthorized"));
|
|
101
|
-
|
|
102
|
-
const result = await refreshCachedSession();
|
|
103
|
-
|
|
104
|
-
expect(result.refreshed).toBe(false);
|
|
105
|
-
expect(result.reason).toContain("NotAuthorized");
|
|
106
|
-
expect(mocks.refreshTokens).not.toHaveBeenCalled();
|
|
107
|
-
expect(mocks.browserLogin).not.toHaveBeenCalled();
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const mocks = vi.hoisted(() => ({
|
|
4
|
-
isMachineIdentity: vi.fn(),
|
|
5
|
-
getValidMachineTokens: vi.fn(),
|
|
6
|
-
mintMachineTokens: vi.fn(),
|
|
7
|
-
loadCachedTokens: vi.fn(),
|
|
8
|
-
refreshTokens: vi.fn(),
|
|
9
|
-
browserLogin: vi.fn(),
|
|
10
|
-
isExpiring: vi.fn(),
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
vi.mock("@indigoai-us/hq-cloud", async (importOriginal) => {
|
|
14
|
-
const actual = await importOriginal<typeof import("@indigoai-us/hq-cloud")>();
|
|
15
|
-
return { ...actual, ...mocks };
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
import { refreshCachedSession } from "./cognito-session.js";
|
|
19
|
-
|
|
20
|
-
const HUMAN_TOKENS = {
|
|
21
|
-
accessToken: "human-access-token",
|
|
22
|
-
idToken: "human-id-token",
|
|
23
|
-
refreshToken: "human-refresh-token",
|
|
24
|
-
expiresAt: Date.now() + 3600_000,
|
|
25
|
-
tokenType: "Bearer" as const,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
vi.resetAllMocks();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe("refreshCachedSession in human mode", () => {
|
|
33
|
-
it("returns no cached session without attempting a refresh", async () => {
|
|
34
|
-
mocks.isMachineIdentity.mockReturnValue(false);
|
|
35
|
-
mocks.loadCachedTokens.mockReturnValue(null);
|
|
36
|
-
|
|
37
|
-
const result = await refreshCachedSession();
|
|
38
|
-
|
|
39
|
-
expect(result).toEqual({ refreshed: false, reason: "no cached session" });
|
|
40
|
-
expect(mocks.refreshTokens).not.toHaveBeenCalled();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("returns success on a healthy cached session without refreshing", async () => {
|
|
44
|
-
mocks.isMachineIdentity.mockReturnValue(false);
|
|
45
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
46
|
-
mocks.isExpiring.mockReturnValue(false);
|
|
47
|
-
|
|
48
|
-
const result = await refreshCachedSession();
|
|
49
|
-
|
|
50
|
-
expect(result).toEqual({ refreshed: true });
|
|
51
|
-
expect(mocks.isExpiring).toHaveBeenCalledWith(HUMAN_TOKENS, 120);
|
|
52
|
-
expect(mocks.refreshTokens).not.toHaveBeenCalled();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("refreshes once when the cached session is expiring", async () => {
|
|
56
|
-
mocks.isMachineIdentity.mockReturnValue(false);
|
|
57
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
58
|
-
mocks.isExpiring.mockReturnValue(true);
|
|
59
|
-
mocks.refreshTokens.mockResolvedValue({
|
|
60
|
-
...HUMAN_TOKENS,
|
|
61
|
-
accessToken: "refreshed-access-token",
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const result = await refreshCachedSession();
|
|
65
|
-
|
|
66
|
-
expect(result).toEqual({ refreshed: true });
|
|
67
|
-
expect(mocks.refreshTokens).toHaveBeenCalledTimes(1);
|
|
68
|
-
expect(mocks.refreshTokens).toHaveBeenCalledWith(
|
|
69
|
-
expect.any(Object),
|
|
70
|
-
HUMAN_TOKENS.refreshToken,
|
|
71
|
-
);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("surfaces refresh failures as a non-throwing result", async () => {
|
|
75
|
-
mocks.isMachineIdentity.mockReturnValue(false);
|
|
76
|
-
mocks.loadCachedTokens.mockReturnValue(HUMAN_TOKENS);
|
|
77
|
-
mocks.isExpiring.mockReturnValue(true);
|
|
78
|
-
mocks.refreshTokens.mockRejectedValue(new Error("token expired"));
|
|
79
|
-
|
|
80
|
-
const result = await refreshCachedSession();
|
|
81
|
-
|
|
82
|
-
expect(result).toEqual({ refreshed: false, reason: "token expired" });
|
|
83
|
-
});
|
|
84
|
-
});
|