@zivis/cli 0.1.0-alpha.5 → 0.1.0-alpha.52

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.
Files changed (197) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +31 -0
  3. package/dist/commands/app/index.d.ts +0 -8
  4. package/dist/commands/app/index.js +8 -18
  5. package/dist/commands/assurance/index.d.ts +35 -0
  6. package/dist/commands/assurance/index.js +154 -0
  7. package/dist/commands/auth/bind.d.ts +4 -0
  8. package/dist/commands/auth/bind.js +97 -0
  9. package/dist/commands/auth/index.js +21 -2
  10. package/dist/commands/auth/init.d.ts +2 -0
  11. package/dist/commands/auth/init.js +248 -96
  12. package/dist/commands/auth/login.d.ts +2 -0
  13. package/dist/commands/auth/login.js +136 -18
  14. package/dist/commands/auth/logout.js +19 -7
  15. package/dist/commands/auth/sessions.js +7 -4
  16. package/dist/commands/auth/status.js +33 -12
  17. package/dist/commands/auth/token.d.ts +4 -0
  18. package/dist/commands/auth/token.js +73 -0
  19. package/dist/commands/check/index.d.ts +2 -0
  20. package/dist/commands/check/index.js +463 -0
  21. package/dist/commands/credits/index.js +2 -3
  22. package/dist/commands/gate/index.d.ts +2 -0
  23. package/dist/commands/gate/index.js +171 -0
  24. package/dist/commands/inspect/index.d.ts +2 -0
  25. package/dist/commands/inspect/index.js +136 -0
  26. package/dist/commands/mcp/index.js +113 -14
  27. package/dist/commands/open/index.d.ts +0 -8
  28. package/dist/commands/open/index.js +0 -11
  29. package/dist/commands/run/index.d.ts +2 -0
  30. package/dist/commands/run/index.js +206 -0
  31. package/dist/commands/scan/index.js +3 -8
  32. package/dist/commands/share/index.d.ts +14 -0
  33. package/dist/commands/share/index.js +100 -0
  34. package/dist/commands/sync/index.d.ts +2 -0
  35. package/dist/commands/sync/index.js +193 -0
  36. package/dist/commands/target/index.js +0 -3
  37. package/dist/commands/test/index.d.ts +2 -0
  38. package/dist/commands/test/index.js +198 -0
  39. package/dist/commands/threatmodel/index.d.ts +2 -0
  40. package/dist/commands/threatmodel/index.js +167 -0
  41. package/dist/index.js +28 -3
  42. package/dist/internal/application-binding.d.ts +8 -0
  43. package/dist/internal/application-binding.js +167 -0
  44. package/dist/internal/binding-token-mint.d.ts +33 -0
  45. package/dist/internal/binding-token-mint.js +174 -0
  46. package/dist/internal/change-recommendation.d.ts +6 -0
  47. package/dist/internal/change-recommendation.js +113 -0
  48. package/dist/internal/cli-output.d.ts +16 -0
  49. package/dist/internal/cli-output.js +39 -0
  50. package/dist/internal/devx-run.d.ts +129 -0
  51. package/dist/internal/devx-run.js +39 -0
  52. package/dist/internal/extractor/adapters/go/index.d.ts +0 -4
  53. package/dist/internal/extractor/adapters/go/index.js +0 -6
  54. package/dist/internal/extractor/adapters/go/manifest.d.ts +0 -17
  55. package/dist/internal/extractor/adapters/go/manifest.js +19 -25
  56. package/dist/internal/extractor/adapters/go/parser.d.ts +0 -4
  57. package/dist/internal/extractor/adapters/go/parser.js +0 -5
  58. package/dist/internal/extractor/adapters/go/scanner.d.ts +0 -20
  59. package/dist/internal/extractor/adapters/go/scanner.js +0 -43
  60. package/dist/internal/extractor/adapters/python/index.d.ts +0 -3
  61. package/dist/internal/extractor/adapters/python/index.js +0 -4
  62. package/dist/internal/extractor/adapters/python/manifest.d.ts +0 -8
  63. package/dist/internal/extractor/adapters/python/manifest.js +21 -18
  64. package/dist/internal/extractor/adapters/python/parser.d.ts +0 -3
  65. package/dist/internal/extractor/adapters/python/parser.js +0 -4
  66. package/dist/internal/extractor/adapters/python/scanner.d.ts +0 -18
  67. package/dist/internal/extractor/adapters/python/scanner.js +1 -54
  68. package/dist/internal/extractor/adapters/typescript/index.d.ts +0 -7
  69. package/dist/internal/extractor/adapters/typescript/index.js +1 -21
  70. package/dist/internal/extractor/adapters/typescript/manifest.d.ts +0 -14
  71. package/dist/internal/extractor/adapters/typescript/manifest.js +26 -17
  72. package/dist/internal/extractor/adapters/typescript/parser.d.ts +0 -8
  73. package/dist/internal/extractor/adapters/typescript/parser.js +0 -9
  74. package/dist/internal/extractor/adapters/typescript/scanner.d.ts +0 -24
  75. package/dist/internal/extractor/adapters/typescript/scanner.js +0 -43
  76. package/dist/internal/extractor/graph-builder.d.ts +10 -0
  77. package/dist/internal/extractor/graph-builder.js +245 -0
  78. package/dist/internal/extractor/graph-types.d.ts +89 -0
  79. package/dist/internal/extractor/graph-types.js +1 -0
  80. package/dist/internal/extractor/index.d.ts +0 -14
  81. package/dist/internal/extractor/index.js +0 -13
  82. package/dist/internal/extractor/types.d.ts +0 -45
  83. package/dist/internal/extractor/types.js +0 -27
  84. package/dist/internal/extractor/walker.d.ts +0 -18
  85. package/dist/internal/extractor/walker.js +0 -18
  86. package/dist/internal/gate-evaluate.d.ts +50 -0
  87. package/dist/internal/gate-evaluate.js +111 -0
  88. package/dist/internal/gate-policy.d.ts +38 -0
  89. package/dist/internal/gate-policy.js +167 -0
  90. package/dist/internal/git-metadata.d.ts +8 -0
  91. package/dist/internal/git-metadata.js +38 -0
  92. package/dist/internal/git.d.ts +9 -0
  93. package/dist/internal/git.js +45 -0
  94. package/dist/internal/github-linkage-prompt.d.ts +7 -0
  95. package/dist/internal/github-linkage-prompt.js +95 -0
  96. package/dist/internal/ide-setup.d.ts +17 -7
  97. package/dist/internal/ide-setup.js +379 -46
  98. package/dist/internal/inventory-sync.d.ts +74 -0
  99. package/dist/internal/inventory-sync.js +189 -0
  100. package/dist/internal/org-picker.d.ts +11 -0
  101. package/dist/internal/org-picker.js +34 -0
  102. package/dist/internal/orgs.js +0 -1
  103. package/dist/internal/packs/cache.d.ts +8 -0
  104. package/dist/internal/packs/cache.js +60 -0
  105. package/dist/internal/packs/index.d.ts +10 -0
  106. package/dist/internal/packs/index.js +8 -0
  107. package/dist/internal/packs/integrity.d.ts +9 -0
  108. package/dist/internal/packs/integrity.js +24 -0
  109. package/dist/internal/packs/jcs.d.ts +2 -0
  110. package/dist/internal/packs/jcs.js +57 -0
  111. package/dist/internal/packs/local-paths.d.ts +4 -0
  112. package/dist/internal/packs/local-paths.js +26 -0
  113. package/dist/internal/packs/npm-registry-client.d.ts +14 -0
  114. package/dist/internal/packs/npm-registry-client.js +87 -0
  115. package/dist/internal/packs/registry-client.d.ts +9 -0
  116. package/dist/internal/packs/registry-client.js +25 -0
  117. package/dist/internal/packs/resolve.d.ts +8 -0
  118. package/dist/internal/packs/resolve.js +89 -0
  119. package/dist/internal/packs/semver.d.ts +9 -0
  120. package/dist/internal/packs/semver.js +57 -0
  121. package/dist/internal/packs/signing.d.ts +5 -0
  122. package/dist/internal/packs/signing.js +56 -0
  123. package/dist/internal/packs/types.d.ts +77 -0
  124. package/dist/internal/packs/types.js +20 -0
  125. package/dist/internal/project-binding.d.ts +1 -0
  126. package/dist/internal/project-binding.js +16 -11
  127. package/dist/internal/resolve-init-session.d.ts +8 -0
  128. package/dist/internal/resolve-init-session.js +36 -0
  129. package/dist/internal/run-workdir.d.ts +2 -0
  130. package/dist/internal/run-workdir.js +19 -0
  131. package/dist/internal/security-context.d.ts +63 -0
  132. package/dist/internal/security-context.js +50 -0
  133. package/dist/internal/sync-outbox.d.ts +40 -0
  134. package/dist/internal/sync-outbox.js +66 -0
  135. package/dist/internal/target-auth/api-config.d.ts +0 -17
  136. package/dist/internal/target-auth/api-config.js +0 -18
  137. package/dist/internal/target-auth/config.d.ts +0 -12
  138. package/dist/internal/target-auth/config.js +0 -13
  139. package/dist/internal/target-auth/index.d.ts +0 -18
  140. package/dist/internal/target-auth/index.js +0 -19
  141. package/dist/internal/target-auth/keychain.d.ts +0 -18
  142. package/dist/internal/target-auth/keychain.js +3 -23
  143. package/dist/internal/target-auth/types.d.ts +0 -26
  144. package/dist/internal/target-auth/types.js +0 -10
  145. package/dist/internal/target-auth/workos.d.ts +0 -15
  146. package/dist/internal/target-auth/workos.js +9 -18
  147. package/dist/internal/test-scope.d.ts +99 -0
  148. package/dist/internal/test-scope.js +101 -0
  149. package/dist/internal/threatmodel-run-state.d.ts +15 -0
  150. package/dist/internal/threatmodel-run-state.js +43 -0
  151. package/dist/internal/threatmodel-run.d.ts +85 -0
  152. package/dist/internal/threatmodel-run.js +159 -0
  153. package/dist/internal/trust-room-link.d.ts +10 -0
  154. package/dist/internal/trust-room-link.js +15 -0
  155. package/dist/internal/zivis-local-state.d.ts +1 -0
  156. package/dist/internal/zivis-local-state.js +22 -0
  157. package/package.json +21 -5
  158. package/dist/commands/app/index.js.map +0 -1
  159. package/dist/commands/auth/index.js.map +0 -1
  160. package/dist/commands/auth/init.js.map +0 -1
  161. package/dist/commands/auth/login.js.map +0 -1
  162. package/dist/commands/auth/logout.js.map +0 -1
  163. package/dist/commands/auth/sessions.js.map +0 -1
  164. package/dist/commands/auth/status.js.map +0 -1
  165. package/dist/commands/credits/index.js.map +0 -1
  166. package/dist/commands/mcp/index.js.map +0 -1
  167. package/dist/commands/open/index.js.map +0 -1
  168. package/dist/commands/scan/index.js.map +0 -1
  169. package/dist/commands/target/index.js.map +0 -1
  170. package/dist/commands/tm/index.d.ts +0 -2
  171. package/dist/commands/tm/index.js +0 -266
  172. package/dist/commands/tm/index.js.map +0 -1
  173. package/dist/index.js.map +0 -1
  174. package/dist/internal/extractor/adapters/go/index.js.map +0 -1
  175. package/dist/internal/extractor/adapters/go/manifest.js.map +0 -1
  176. package/dist/internal/extractor/adapters/go/parser.js.map +0 -1
  177. package/dist/internal/extractor/adapters/go/scanner.js.map +0 -1
  178. package/dist/internal/extractor/adapters/python/index.js.map +0 -1
  179. package/dist/internal/extractor/adapters/python/manifest.js.map +0 -1
  180. package/dist/internal/extractor/adapters/python/parser.js.map +0 -1
  181. package/dist/internal/extractor/adapters/python/scanner.js.map +0 -1
  182. package/dist/internal/extractor/adapters/typescript/index.js.map +0 -1
  183. package/dist/internal/extractor/adapters/typescript/manifest.js.map +0 -1
  184. package/dist/internal/extractor/adapters/typescript/parser.js.map +0 -1
  185. package/dist/internal/extractor/adapters/typescript/scanner.js.map +0 -1
  186. package/dist/internal/extractor/index.js.map +0 -1
  187. package/dist/internal/extractor/types.js.map +0 -1
  188. package/dist/internal/extractor/walker.js.map +0 -1
  189. package/dist/internal/ide-setup.js.map +0 -1
  190. package/dist/internal/orgs.js.map +0 -1
  191. package/dist/internal/project-binding.js.map +0 -1
  192. package/dist/internal/target-auth/api-config.js.map +0 -1
  193. package/dist/internal/target-auth/config.js.map +0 -1
  194. package/dist/internal/target-auth/index.js.map +0 -1
  195. package/dist/internal/target-auth/keychain.js.map +0 -1
  196. package/dist/internal/target-auth/types.js.map +0 -1
  197. package/dist/internal/target-auth/workos.js.map +0 -1
@@ -1,14 +1,3 @@
1
- /**
2
- * Fetches an Application's auth config from the ZIVIS platform.
3
- *
4
- * Phase J.4: replaces the local `~/.config/zivis/target-configs/*.json`
5
- * file the user previously had to write by hand. The Application's IdP
6
- * discovery (clientId, domain, mode, scopes) lives on the Application
7
- * record on the platform; the CLI calls this endpoint to learn how to
8
- * PKCE-auth, then runs the flow locally and stores tokens in the user's
9
- * keychain. Tokens never leave the user's machine unless the user
10
- * explicitly ships them with a scenario-run trigger.
11
- */
12
1
  import type { TargetAuthConfig, WorkosMode } from "./types.js";
13
2
  interface AuthConfigResponse {
14
3
  applicationId: string;
@@ -27,11 +16,5 @@ interface AuthConfigResponse {
27
16
  error?: string;
28
17
  }
29
18
  export declare function fetchAuthConfig(applicationId: string, sessionName?: string): Promise<AuthConfigResponse>;
30
- /**
31
- * Adapt the platform's auth-config response into the local TargetAuthConfig
32
- * shape that the existing PKCE flow consumes. Throws when the application
33
- * isn't OAuth-PKCE-shaped (e.g., static_token, client_credentials) — the
34
- * caller should give a useful error and direct the user elsewhere.
35
- */
36
19
  export declare function adaptToWorkosConfig(resp: AuthConfigResponse): TargetAuthConfig;
37
20
  export {};
@@ -1,14 +1,3 @@
1
- /**
2
- * Fetches an Application's auth config from the ZIVIS platform.
3
- *
4
- * Phase J.4: replaces the local `~/.config/zivis/target-configs/*.json`
5
- * file the user previously had to write by hand. The Application's IdP
6
- * discovery (clientId, domain, mode, scopes) lives on the Application
7
- * record on the platform; the CLI calls this endpoint to learn how to
8
- * PKCE-auth, then runs the flow locally and stores tokens in the user's
9
- * keychain. Tokens never leave the user's machine unless the user
10
- * explicitly ships them with a scenario-run trigger.
11
- */
12
1
  import { ApiClient } from "@zivis/mcp/api-client";
13
2
  import { DEFAULT_CONFIG } from "@zivis/mcp/types";
14
3
  export async function fetchAuthConfig(applicationId, sessionName) {
@@ -18,12 +7,6 @@ export async function fetchAuthConfig(applicationId, sessionName) {
18
7
  const client = new ApiClient(config);
19
8
  return client.request("GET", `/api/applications/${encodeURIComponent(applicationId)}/auth-config`);
20
9
  }
21
- /**
22
- * Adapt the platform's auth-config response into the local TargetAuthConfig
23
- * shape that the existing PKCE flow consumes. Throws when the application
24
- * isn't OAuth-PKCE-shaped (e.g., static_token, client_credentials) — the
25
- * caller should give a useful error and direct the user elsewhere.
26
- */
27
10
  export function adaptToWorkosConfig(resp) {
28
11
  if (!resp.oauth) {
29
12
  throw new Error(resp.hint || resp.error ||
@@ -37,4 +20,3 @@ export function adaptToWorkosConfig(resp) {
37
20
  extraScopes: resp.oauth.scopes,
38
21
  };
39
22
  }
40
- //# sourceMappingURL=api-config.js.map
@@ -1,15 +1,3 @@
1
- /**
2
- * Target-auth config storage (local-only, v1).
3
- *
4
- * Per-target IdP config (domain, client_id, mode, callback port) lives under
5
- * `~/.config/zivis/target-configs/<targetId>.json`. This is *config*, not
6
- * credentials — safe to commit a sanitized version to your repo if you want
7
- * teammates to share it.
8
- *
9
- * v2: ZIVIS will serve target-auth config from the API so any team member's
10
- * CLI can discover it. For now, configure once locally with `zivis target
11
- * configure` and check in the file if you want it shared.
12
- */
13
1
  import type { TargetAuthConfig } from "./types.js";
14
2
  export declare function loadTargetConfig(targetId: string): Promise<TargetAuthConfig | null>;
15
3
  export declare function saveTargetConfig(targetId: string, cfg: TargetAuthConfig): Promise<string>;
@@ -1,15 +1,3 @@
1
- /**
2
- * Target-auth config storage (local-only, v1).
3
- *
4
- * Per-target IdP config (domain, client_id, mode, callback port) lives under
5
- * `~/.config/zivis/target-configs/<targetId>.json`. This is *config*, not
6
- * credentials — safe to commit a sanitized version to your repo if you want
7
- * teammates to share it.
8
- *
9
- * v2: ZIVIS will serve target-auth config from the API so any team member's
10
- * CLI can discover it. For now, configure once locally with `zivis target
11
- * configure` and check in the file if you want it shared.
12
- */
13
1
  import * as fs from "node:fs/promises";
14
2
  import * as path from "node:path";
15
3
  import * as os from "node:os";
@@ -55,4 +43,3 @@ export async function listTargetConfigs() {
55
43
  export function getConfigPath(targetId) {
56
44
  return configPath(targetId);
57
45
  }
58
- //# sourceMappingURL=config.js.map
@@ -1,23 +1,5 @@
1
- /**
2
- * Target-auth orchestrator: load config, run the right IdP flow, manage tokens.
3
- *
4
- * Public API:
5
- * getValidTargetToken(targetId, persona) — returns access_token; refreshes if near expiry
6
- * loginTarget(targetId, persona) — runs the appropriate IdP flow
7
- * logoutTarget(targetId, persona) — clears stored tokens
8
- *
9
- * Designed so RT-runner-side ephemeral cred plumbing only sees a flat
10
- * { accessToken, refreshToken?, expiresAt, idpType } bundle — no IdP
11
- * specifics leak past this boundary.
12
- */
13
1
  import type { EphemeralTargetCreds, TargetTokens } from "./types.js";
14
2
  export declare function loginTarget(targetId: string, persona: string): Promise<TargetTokens>;
15
- /**
16
- * J.4 path: log in against an Application by id. Auth config comes from
17
- * the platform (no local config file required). Tokens are stored under
18
- * the existing keychain namespace using applicationId as the key — same
19
- * keychain layout, no migration needed for already-stored tokens.
20
- */
21
3
  export declare function loginApplication(applicationId: string, persona: string, sessionName?: string): Promise<TargetTokens>;
22
4
  export declare function logoutTarget(targetId: string, persona: string): Promise<void>;
23
5
  export declare function getValidTargetToken(targetId: string, persona: string): Promise<TargetTokens | null>;
@@ -1,15 +1,3 @@
1
- /**
2
- * Target-auth orchestrator: load config, run the right IdP flow, manage tokens.
3
- *
4
- * Public API:
5
- * getValidTargetToken(targetId, persona) — returns access_token; refreshes if near expiry
6
- * loginTarget(targetId, persona) — runs the appropriate IdP flow
7
- * logoutTarget(targetId, persona) — clears stored tokens
8
- *
9
- * Designed so RT-runner-side ephemeral cred plumbing only sees a flat
10
- * { accessToken, refreshToken?, expiresAt, idpType } bundle — no IdP
11
- * specifics leak past this boundary.
12
- */
13
1
  import { loadTargetConfig } from "./config.js";
14
2
  import { loadTokens, storeTokens, deleteTokens } from "./keychain.js";
15
3
  import { loginWorkos, refreshWorkos } from "./workos.js";
@@ -21,12 +9,6 @@ export async function loginTarget(targetId, persona) {
21
9
  await storeTokens(targetId, persona, tokens);
22
10
  return tokens;
23
11
  }
24
- /**
25
- * J.4 path: log in against an Application by id. Auth config comes from
26
- * the platform (no local config file required). Tokens are stored under
27
- * the existing keychain namespace using applicationId as the key — same
28
- * keychain layout, no migration needed for already-stored tokens.
29
- */
30
12
  export async function loginApplication(applicationId, persona, sessionName) {
31
13
  const resp = await fetchAuthConfig(applicationId, sessionName);
32
14
  const cfg = adaptToWorkosConfig(resp);
@@ -98,4 +80,3 @@ async function runRefresh(cfg, refreshToken) {
98
80
  throw new Error(`Unsupported IdP type: ${cfg.type}`);
99
81
  }
100
82
  }
101
- //# sourceMappingURL=index.js.map
@@ -1,21 +1,3 @@
1
- /**
2
- * Target-auth keychain.
3
- *
4
- * Distinct namespace from the user's ZIVIS-platform tokens (handled by
5
- * `zivis-mcp-security`'s keychain module). A user can be logged into
6
- * ZIVIS itself AND to N customer-target IdPs simultaneously, each with
7
- * multiple personas (admin, user_a, …) for permutation testing.
8
- *
9
- * Storage layout
10
- * service: zivis.target.<targetId>.<persona>
11
- * account: zivis-target
12
- * value: JSON-serialised TargetTokens
13
- *
14
- * macOS-only for v1 (matches the engagement helper). Linux/Windows fall
15
- * back to an encrypted file on disk; the underlying impl lives in
16
- * `@zivis/mcp/auth/keychain.ts` for the platform login — we
17
- * deliberately don't share that module to keep the namespaces isolated.
18
- */
19
1
  import type { TargetTokens } from "./types.js";
20
2
  export declare function storeTokens(targetId: string, persona: string, tokens: TargetTokens): Promise<void>;
21
3
  export declare function loadTokens(targetId: string, persona: string): Promise<TargetTokens | null>;
@@ -1,21 +1,3 @@
1
- /**
2
- * Target-auth keychain.
3
- *
4
- * Distinct namespace from the user's ZIVIS-platform tokens (handled by
5
- * `zivis-mcp-security`'s keychain module). A user can be logged into
6
- * ZIVIS itself AND to N customer-target IdPs simultaneously, each with
7
- * multiple personas (admin, user_a, …) for permutation testing.
8
- *
9
- * Storage layout
10
- * service: zivis.target.<targetId>.<persona>
11
- * account: zivis-target
12
- * value: JSON-serialised TargetTokens
13
- *
14
- * macOS-only for v1 (matches the engagement helper). Linux/Windows fall
15
- * back to an encrypted file on disk; the underlying impl lives in
16
- * `@zivis/mcp/auth/keychain.ts` for the platform login — we
17
- * deliberately don't share that module to keep the namespaces isolated.
18
- */
19
1
  import { execFile } from "node:child_process";
20
2
  import { promisify } from "node:util";
21
3
  import * as fs from "node:fs/promises";
@@ -33,7 +15,6 @@ function fallbackPath(targetId, persona) {
33
15
  return path.join(dir, `${targetId}.${persona}.enc`);
34
16
  }
35
17
  function fallbackKey() {
36
- // Same scheme as the platform-side keychain fallback: derive from username.
37
18
  return new Uint8Array(crypto.scryptSync(os.userInfo().username || "zivis", "zivis-target-salt", 32));
38
19
  }
39
20
  async function macStore(targetId, persona, value) {
@@ -42,7 +23,7 @@ async function macStore(targetId, persona, value) {
42
23
  "delete-generic-password", "-a", ACCOUNT, "-s", svc(targetId, persona),
43
24
  ]);
44
25
  }
45
- catch { /* not present */ }
26
+ catch { }
46
27
  await execFileAsync("security", [
47
28
  "add-generic-password", "-a", ACCOUNT, "-s", svc(targetId, persona), "-w", value,
48
29
  ]);
@@ -64,7 +45,7 @@ async function macDelete(targetId, persona) {
64
45
  "delete-generic-password", "-a", ACCOUNT, "-s", svc(targetId, persona),
65
46
  ]);
66
47
  }
67
- catch { /* not present */ }
48
+ catch { }
68
49
  }
69
50
  async function fileStore(targetId, persona, value) {
70
51
  const p = fallbackPath(targetId, persona);
@@ -105,7 +86,7 @@ async function fileDelete(targetId, persona) {
105
86
  try {
106
87
  await fs.unlink(fallbackPath(targetId, persona));
107
88
  }
108
- catch { /* not present */ }
89
+ catch { }
109
90
  }
110
91
  async function tryMac() {
111
92
  if (process.platform !== "darwin")
@@ -147,4 +128,3 @@ export function getStorageName() {
147
128
  ? "macOS Keychain"
148
129
  : "encrypted file (~/.config/zivis/target-tokens)";
149
130
  }
150
- //# sourceMappingURL=keychain.js.map
@@ -1,51 +1,25 @@
1
- /**
2
- * Target-auth: PKCE auth flows against the *customer's* identity provider.
3
- *
4
- * The user authenticates locally against the target system's IdP. Tokens
5
- * stay in the user's OS keychain. When a scenario run is triggered, the
6
- * CLI ships a short-lived access token (and optionally a refresh token)
7
- * to the ZIVIS platform, which uses it for the duration of the run only.
8
- * ZIVIS never persists target-system credentials.
9
- */
10
1
  export type IdpType = "workos" | "auth0" | "apikey" | "none";
11
- /** WorkOS path layout — three observed flavors. */
12
2
  export type WorkosMode = "user_management" | "authkit" | "workos";
13
3
  export interface WorkosConfig {
14
4
  type: "workos";
15
- /** WorkOS client_id (AuthKit application). */
16
5
  clientId: string;
17
- /**
18
- * Auth host. e.g. `api.workos.com` (user_management/legacy) or
19
- * `<custom>.authkit.app` (custom AuthKit domain).
20
- */
21
6
  domain: string;
22
- /** Path layout flavor. Defaults to `user_management`. */
23
7
  mode?: WorkosMode;
24
- /** localhost callback port for the PKCE redirect. Defaults to 5174. */
25
8
  callbackPort?: number;
26
- /** Extra OAuth scopes beyond `openid profile email offline_access`. */
27
9
  extraScopes?: string[];
28
10
  }
29
11
  export type TargetAuthConfig = WorkosConfig;
30
12
  export interface TargetTokens {
31
- /** OAuth access token. */
32
13
  access_token: string;
33
- /** OAuth refresh token, if the IdP issued one. */
34
14
  refresh_token?: string;
35
- /** Unix-ms expiry, derived from JWT exp claim or `expires_in`. */
36
15
  expires_at: number;
37
- /** Optional id_token for client-side claim inspection. */
38
16
  id_token?: string;
39
- /** When this token bundle was obtained (unix-ms). */
40
17
  obtained_at: number;
41
18
  }
42
- /** Bundle shipped to ZIVIS on `scenario run` — RT consumes ephemerally. */
43
19
  export interface EphemeralTargetCreds {
44
20
  idpType: IdpType;
45
21
  accessToken: string;
46
22
  refreshToken?: string;
47
- /** Unix-ms expiry of the access token. */
48
23
  expiresAt: number;
49
- /** Echo of the persona, useful for audit logs. */
50
24
  persona?: string;
51
25
  }
@@ -1,11 +1 @@
1
- /**
2
- * Target-auth: PKCE auth flows against the *customer's* identity provider.
3
- *
4
- * The user authenticates locally against the target system's IdP. Tokens
5
- * stay in the user's OS keychain. When a scenario run is triggered, the
6
- * CLI ships a short-lived access token (and optionally a refresh token)
7
- * to the ZIVIS platform, which uses it for the duration of the run only.
8
- * ZIVIS never persists target-system credentials.
9
- */
10
1
  export {};
11
- //# sourceMappingURL=types.js.map
@@ -1,18 +1,3 @@
1
- /**
2
- * WorkOS PKCE login + refresh against a *target* IdP.
3
- *
4
- * Adapted from `zivis-rt/specs/engagements/meshmesh-cred-threat-model/scripts/authkit-helper.mjs`,
5
- * which is itself adapted from `@zivis/mcp/src/auth/oauth.ts`. Three
6
- * known WorkOS flavors are supported:
7
- * - user_management — api.workos.com/user_management/{authorize,authenticate}
8
- * - authkit — <custom>.authkit.app/oauth2/{authorize,token}
9
- * - workos — legacy auth.workos.com/{authorize,oauth/token}
10
- *
11
- * Why a copy and not a shared module: the platform-side login uses a fixed
12
- * client_id and our own AuthKit. Target login uses the *customer's* IdP
13
- * config, parameterized per target. Same primitives, different config
14
- * surface — keeping them separate avoids accidental cross-tenant token mixing.
15
- */
16
1
  import type { TargetTokens, WorkosConfig } from "./types.js";
17
2
  export declare function decodeJwtPayload(jwt: string): Record<string, unknown> | null;
18
3
  declare function refreshTokens(cfg: WorkosConfig, refreshToken: string): Promise<TargetTokens>;
@@ -1,18 +1,3 @@
1
- /**
2
- * WorkOS PKCE login + refresh against a *target* IdP.
3
- *
4
- * Adapted from `zivis-rt/specs/engagements/meshmesh-cred-threat-model/scripts/authkit-helper.mjs`,
5
- * which is itself adapted from `@zivis/mcp/src/auth/oauth.ts`. Three
6
- * known WorkOS flavors are supported:
7
- * - user_management — api.workos.com/user_management/{authorize,authenticate}
8
- * - authkit — <custom>.authkit.app/oauth2/{authorize,token}
9
- * - workos — legacy auth.workos.com/{authorize,oauth/token}
10
- *
11
- * Why a copy and not a shared module: the platform-side login uses a fixed
12
- * client_id and our own AuthKit. Target login uses the *customer's* IdP
13
- * config, parameterized per target. Same primitives, different config
14
- * surface — keeping them separate avoids accidental cross-tenant token mixing.
15
- */
16
1
  import * as crypto from "node:crypto";
17
2
  import * as http from "node:http";
18
3
  import { execFile } from "node:child_process";
@@ -69,12 +54,20 @@ function tokensFromResponse(d, prevRefresh) {
69
54
  obtained_at: Date.now(),
70
55
  };
71
56
  }
57
+ function escapeHtml(s) {
58
+ return s
59
+ .replace(/&/g, "&amp;")
60
+ .replace(/</g, "&lt;")
61
+ .replace(/>/g, "&gt;")
62
+ .replace(/"/g, "&quot;")
63
+ .replace(/'/g, "&#39;");
64
+ }
72
65
  function htmlPage(success, msg = "") {
73
66
  const title = success ? "Authenticated" : "Auth failed";
74
67
  const color = success ? "#00d4aa" : "#ff5252";
75
68
  return `<!DOCTYPE html><html><head><title>${title}</title></head>
76
69
  <body style="font-family:system-ui;text-align:center;padding:50px;background:#0f0f1a;color:#fff;">
77
- <h1 style="color:${color};">${title}</h1><p>${msg}</p>
70
+ <h1 style="color:${color};">${title}</h1><p>${escapeHtml(msg)}</p>
78
71
  <p>You can close this window.</p><script>setTimeout(()=>window.close(),1500);</script>
79
72
  </body></html>`;
80
73
  }
@@ -185,7 +178,6 @@ export async function loginWorkos(cfg, persona) {
185
178
  await open(authUrl);
186
179
  }
187
180
  catch {
188
- // open() can fail in headless envs — print the URL and let the user click.
189
181
  await execFileAsync("printf", [authUrl]).catch(() => { });
190
182
  process.stderr.write(`[zivis] open ${authUrl}\n`);
191
183
  }
@@ -193,4 +185,3 @@ export async function loginWorkos(cfg, persona) {
193
185
  return exchangeCode(cfg, code, verifier);
194
186
  }
195
187
  export { refreshTokens as refreshWorkos };
196
- //# sourceMappingURL=workos.js.map
@@ -0,0 +1,99 @@
1
+ import { type DevXRunApi } from "./devx-run.js";
2
+ import { type SecurityContextApi, type SecurityContextOutcome } from "./security-context.js";
3
+ import type { PackRegistryClient, PackTestEntry } from "./packs/types.js";
4
+ export interface TestRunDeps {
5
+ apiClient: DevXRunApi & SecurityContextApi;
6
+ registryClient: PackRegistryClient;
7
+ }
8
+ export interface StartTestRunParams {
9
+ applicationId: string;
10
+ scopeId?: string;
11
+ cwd: string;
12
+ cliVersion: string;
13
+ precomputedContext?: SecurityContextOutcome;
14
+ }
15
+ export interface ResolvedScopeSummary {
16
+ id: string;
17
+ label: string;
18
+ tests: PackTestEntry[];
19
+ }
20
+ export interface TestRunEnvelope {
21
+ run_id: string;
22
+ application: {
23
+ id: string;
24
+ };
25
+ connection: {
26
+ mode: "connected";
27
+ };
28
+ git: {
29
+ sha: string | null;
30
+ dirty: boolean | null;
31
+ };
32
+ methodology: {
33
+ pack: string;
34
+ version: string;
35
+ path: string;
36
+ scope?: {
37
+ id: string;
38
+ label: string;
39
+ path: string;
40
+ };
41
+ };
42
+ context: {
43
+ path: string;
44
+ };
45
+ scope: ResolvedScopeSummary | null;
46
+ requested_intent: {
47
+ scope: string;
48
+ } | null;
49
+ result_contract: {
50
+ schema_version: string;
51
+ complete_command: string;
52
+ };
53
+ agent_instructions: string[];
54
+ }
55
+ export interface StartTestRunResult {
56
+ envelope: TestRunEnvelope;
57
+ resolvedScope: ResolvedScopeSummary | null;
58
+ contextOutcome: SecurityContextOutcome;
59
+ }
60
+ export declare function startTestRun(deps: TestRunDeps, params: StartTestRunParams): Promise<StartTestRunResult>;
61
+ export type ChangeRecommendationOutcome = {
62
+ kind: "no-prior-context";
63
+ contextOutcome: SecurityContextOutcome;
64
+ } | {
65
+ kind: "sha-not-found";
66
+ sha: string;
67
+ contextOutcome: SecurityContextOutcome;
68
+ } | {
69
+ kind: "up-to-date";
70
+ sha: string;
71
+ } | {
72
+ kind: "no-scope-match";
73
+ sha: string;
74
+ changedFileCount: number;
75
+ } | {
76
+ kind: "recommendation";
77
+ sha: string;
78
+ changedFileCount: number;
79
+ scopes: {
80
+ id: string;
81
+ label: string;
82
+ }[];
83
+ testIds: string[];
84
+ };
85
+ export declare function tryBuildChangeRecommendation(deps: TestRunDeps, params: {
86
+ applicationId: string;
87
+ cwd: string;
88
+ cliVersion: string;
89
+ }): Promise<ChangeRecommendationOutcome>;
90
+ export interface TestScopeListing {
91
+ pack: string;
92
+ version: string;
93
+ scopes: {
94
+ id: string;
95
+ label: string;
96
+ description: string;
97
+ }[];
98
+ }
99
+ export declare function listTestScopes(registryClient: PackRegistryClient, cliVersion: string): Promise<TestScopeListing>;
@@ -0,0 +1,101 @@
1
+ import { readGitMetadata, getChangedFilesSince } from "./git.js";
2
+ import { startDevXRun, DEVX_RUN_CONTRACT_VERSION } from "./devx-run.js";
3
+ import { fetchSecurityContext } from "./security-context.js";
4
+ import { resolveCompatiblePack, resolveScope, listAvailableScopes } from "./packs/resolve.js";
5
+ import { writeRunWorkFile } from "./run-workdir.js";
6
+ import { buildChangeRecommendation } from "./change-recommendation.js";
7
+ function scopeContentPath(resolved, scopeId) {
8
+ const entry = resolved.scopes.find((s) => s.id === scopeId);
9
+ return entry ? `${resolved.cacheDir}/${entry.path}` : resolved.cacheDir;
10
+ }
11
+ function formatDeclaredTestCatalog(tests) {
12
+ return tests
13
+ .filter((t) => !t.deprecated)
14
+ .map((t) => `${t.id} — ${t.title}`)
15
+ .join("; ");
16
+ }
17
+ function buildAgentInstructions(resolvedScope) {
18
+ if (resolvedScope) {
19
+ const catalog = formatDeclaredTestCatalog(resolvedScope.tests);
20
+ return [
21
+ `Read the base methodology and the "${resolvedScope.label}" scope guidance at methodology.scope.path.`,
22
+ `Focus this review on the "${resolvedScope.label}" scope. Requested intent is scope=${resolvedScope.id} — this does not mean other areas were evaluated.`,
23
+ ...(catalog
24
+ ? [
25
+ `This scope's declared test catalog: ${catalog}. When you emit observations[].test_id, use exactly one of these declared ids for the check you actually ran — never invent a slug from the prose. If none of them matches what you ran, do not fabricate a new id; describe it in coverage_note instead.`,
26
+ ]
27
+ : []),
28
+ `You may report incidental findings outside this scope if you actually find them, but keep result provenance honest: do not claim coverage you did not perform.`,
29
+ `Use your own repository understanding, shell, and tools to perform the review. When finished, complete the run using result_contract.complete_command.`,
30
+ ];
31
+ }
32
+ return [
33
+ `Read the methodology at methodology.path and perform a full, adaptive AppSec review — decide applicability yourself rather than mechanically executing every category.`,
34
+ `Each scope you apply declares its own stable, permanent test catalog (tests[] in the pack manifest, e.g. AUTH-001, UPLOAD-002 — see the scope's manifest entry). When you emit observations[].test_id, use the declared id for the check you actually ran — never invent a slug from the prose.`,
35
+ `Use your own repository understanding, shell, and tools to perform the review. When finished, complete the run using result_contract.complete_command.`,
36
+ ];
37
+ }
38
+ export async function startTestRun(deps, params) {
39
+ const [git, contextOutcome, resolvedPack] = await Promise.all([
40
+ readGitMetadata(params.cwd),
41
+ params.precomputedContext ?? fetchSecurityContext(deps.apiClient, params.applicationId),
42
+ resolveCompatiblePack("appsec", { registryClient: deps.registryClient, cliVersion: params.cliVersion }),
43
+ ]);
44
+ const scope = params.scopeId ? await resolveScope(resolvedPack, params.scopeId) : null;
45
+ const resolvedScope = scope ? { id: scope.id, label: scope.label, tests: scope.tests } : null;
46
+ const started = await startDevXRun(deps.apiClient, {
47
+ applicationId: params.applicationId,
48
+ runType: "test",
49
+ requestedIntent: resolvedScope ? { scope: resolvedScope.id } : undefined,
50
+ pack: { packId: resolvedPack.packId, packType: resolvedPack.packType, version: resolvedPack.version },
51
+ cwd: params.cwd,
52
+ });
53
+ const contextPath = writeRunWorkFile(params.cwd, started.runId, "context.json", contextOutcome);
54
+ const envelope = {
55
+ run_id: started.runId,
56
+ application: { id: params.applicationId },
57
+ connection: { mode: "connected" },
58
+ git: { sha: git.commitSha ?? null, dirty: git.dirty ?? null },
59
+ methodology: {
60
+ pack: resolvedPack.packType,
61
+ version: resolvedPack.version,
62
+ path: resolvedPack.basePath,
63
+ ...(resolvedScope ? { scope: { id: resolvedScope.id, label: resolvedScope.label, path: scopeContentPath(resolvedPack, resolvedScope.id) } } : {}),
64
+ },
65
+ context: { path: contextPath },
66
+ scope: resolvedScope,
67
+ requested_intent: resolvedScope ? { scope: resolvedScope.id } : null,
68
+ result_contract: {
69
+ schema_version: DEVX_RUN_CONTRACT_VERSION,
70
+ complete_command: `zivis run complete ${started.runId} --input <result.json> --json`,
71
+ },
72
+ agent_instructions: buildAgentInstructions(resolvedScope),
73
+ };
74
+ return { envelope, resolvedScope, contextOutcome };
75
+ }
76
+ export async function tryBuildChangeRecommendation(deps, params) {
77
+ const contextOutcome = await fetchSecurityContext(deps.apiClient, params.applicationId);
78
+ const sha = contextOutcome.available ? contextOutcome.context.lastTestedGitSha : null;
79
+ if (!sha)
80
+ return { kind: "no-prior-context", contextOutcome };
81
+ const changedFiles = await getChangedFilesSince(params.cwd, sha);
82
+ if (changedFiles === undefined)
83
+ return { kind: "sha-not-found", sha, contextOutcome };
84
+ if (changedFiles.length === 0)
85
+ return { kind: "up-to-date", sha };
86
+ const resolvedPack = await resolveCompatiblePack("appsec", { registryClient: deps.registryClient, cliVersion: params.cliVersion });
87
+ const recommendation = buildChangeRecommendation(changedFiles, resolvedPack.scopes);
88
+ if (!recommendation)
89
+ return { kind: "no-scope-match", sha, changedFileCount: changedFiles.length };
90
+ const scopesById = new Map(resolvedPack.scopes.map((s) => [s.id, s]));
91
+ const scopes = recommendation.scopeIds.map((id) => ({ id, label: scopesById.get(id).label }));
92
+ return { kind: "recommendation", sha, changedFileCount: changedFiles.length, scopes, testIds: recommendation.testIds };
93
+ }
94
+ export async function listTestScopes(registryClient, cliVersion) {
95
+ const resolvedPack = await resolveCompatiblePack("appsec", { registryClient, cliVersion });
96
+ return {
97
+ pack: resolvedPack.packType,
98
+ version: resolvedPack.version,
99
+ scopes: listAvailableScopes(resolvedPack),
100
+ };
101
+ }
@@ -0,0 +1,15 @@
1
+ export declare const THREATMODEL_RUN_STATE_FILENAME = "threatmodel-run.json";
2
+ export interface ThreatModelRunState {
3
+ runId: string;
4
+ runType: "threatmodel";
5
+ applicationId: string;
6
+ startedAt: string;
7
+ status: "pending" | "completed";
8
+ packId: string;
9
+ packType: string;
10
+ packVersion: string;
11
+ }
12
+ export declare function recordThreatModelRunState(cwd: string, state: ThreatModelRunState): string;
13
+ export declare function loadThreatModelRunState(cwd: string, runId: string): ThreatModelRunState | null;
14
+ export declare function markThreatModelRunCompleted(cwd: string, runId: string): void;
15
+ export declare function findActiveThreatModelRun(cwd: string): ThreatModelRunState | null;
@@ -0,0 +1,43 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { writeRunWorkFile } from "./run-workdir.js";
4
+ export const THREATMODEL_RUN_STATE_FILENAME = "threatmodel-run.json";
5
+ export function recordThreatModelRunState(cwd, state) {
6
+ return writeRunWorkFile(cwd, state.runId, THREATMODEL_RUN_STATE_FILENAME, state);
7
+ }
8
+ function runStatePath(cwd, runId) {
9
+ return path.join(cwd, ".zivis", "work", runId, THREATMODEL_RUN_STATE_FILENAME);
10
+ }
11
+ export function loadThreatModelRunState(cwd, runId) {
12
+ const filePath = runStatePath(cwd, runId);
13
+ if (!fs.existsSync(filePath))
14
+ return null;
15
+ try {
16
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export function markThreatModelRunCompleted(cwd, runId) {
23
+ const filePath = runStatePath(cwd, runId);
24
+ const existing = loadThreatModelRunState(cwd, runId);
25
+ if (!existing)
26
+ return;
27
+ fs.writeFileSync(filePath, JSON.stringify({ ...existing, status: "completed" }, null, 2) + "\n");
28
+ }
29
+ export function findActiveThreatModelRun(cwd) {
30
+ const workDir = path.join(cwd, ".zivis", "work");
31
+ if (!fs.existsSync(workDir))
32
+ return null;
33
+ const candidates = [];
34
+ for (const runId of fs.readdirSync(workDir)) {
35
+ const state = loadThreatModelRunState(cwd, runId);
36
+ if (state && state.status === "pending")
37
+ candidates.push(state);
38
+ }
39
+ if (candidates.length === 0)
40
+ return null;
41
+ candidates.sort((a, b) => (a.startedAt < b.startedAt ? 1 : -1));
42
+ return candidates[0];
43
+ }