@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.
- package/LICENSE +201 -0
- package/README.md +31 -0
- package/dist/commands/app/index.d.ts +0 -8
- package/dist/commands/app/index.js +8 -18
- package/dist/commands/assurance/index.d.ts +35 -0
- package/dist/commands/assurance/index.js +154 -0
- package/dist/commands/auth/bind.d.ts +4 -0
- package/dist/commands/auth/bind.js +97 -0
- package/dist/commands/auth/index.js +21 -2
- package/dist/commands/auth/init.d.ts +2 -0
- package/dist/commands/auth/init.js +248 -96
- package/dist/commands/auth/login.d.ts +2 -0
- package/dist/commands/auth/login.js +136 -18
- package/dist/commands/auth/logout.js +19 -7
- package/dist/commands/auth/sessions.js +7 -4
- package/dist/commands/auth/status.js +33 -12
- package/dist/commands/auth/token.d.ts +4 -0
- package/dist/commands/auth/token.js +73 -0
- package/dist/commands/check/index.d.ts +2 -0
- package/dist/commands/check/index.js +463 -0
- package/dist/commands/credits/index.js +2 -3
- package/dist/commands/gate/index.d.ts +2 -0
- package/dist/commands/gate/index.js +171 -0
- package/dist/commands/inspect/index.d.ts +2 -0
- package/dist/commands/inspect/index.js +136 -0
- package/dist/commands/mcp/index.js +113 -14
- package/dist/commands/open/index.d.ts +0 -8
- package/dist/commands/open/index.js +0 -11
- package/dist/commands/run/index.d.ts +2 -0
- package/dist/commands/run/index.js +206 -0
- package/dist/commands/scan/index.js +3 -8
- package/dist/commands/share/index.d.ts +14 -0
- package/dist/commands/share/index.js +100 -0
- package/dist/commands/sync/index.d.ts +2 -0
- package/dist/commands/sync/index.js +193 -0
- package/dist/commands/target/index.js +0 -3
- package/dist/commands/test/index.d.ts +2 -0
- package/dist/commands/test/index.js +198 -0
- package/dist/commands/threatmodel/index.d.ts +2 -0
- package/dist/commands/threatmodel/index.js +167 -0
- package/dist/index.js +28 -3
- package/dist/internal/application-binding.d.ts +8 -0
- package/dist/internal/application-binding.js +167 -0
- package/dist/internal/binding-token-mint.d.ts +33 -0
- package/dist/internal/binding-token-mint.js +174 -0
- package/dist/internal/change-recommendation.d.ts +6 -0
- package/dist/internal/change-recommendation.js +113 -0
- package/dist/internal/cli-output.d.ts +16 -0
- package/dist/internal/cli-output.js +39 -0
- package/dist/internal/devx-run.d.ts +129 -0
- package/dist/internal/devx-run.js +39 -0
- package/dist/internal/extractor/adapters/go/index.d.ts +0 -4
- package/dist/internal/extractor/adapters/go/index.js +0 -6
- package/dist/internal/extractor/adapters/go/manifest.d.ts +0 -17
- package/dist/internal/extractor/adapters/go/manifest.js +19 -25
- package/dist/internal/extractor/adapters/go/parser.d.ts +0 -4
- package/dist/internal/extractor/adapters/go/parser.js +0 -5
- package/dist/internal/extractor/adapters/go/scanner.d.ts +0 -20
- package/dist/internal/extractor/adapters/go/scanner.js +0 -43
- package/dist/internal/extractor/adapters/python/index.d.ts +0 -3
- package/dist/internal/extractor/adapters/python/index.js +0 -4
- package/dist/internal/extractor/adapters/python/manifest.d.ts +0 -8
- package/dist/internal/extractor/adapters/python/manifest.js +21 -18
- package/dist/internal/extractor/adapters/python/parser.d.ts +0 -3
- package/dist/internal/extractor/adapters/python/parser.js +0 -4
- package/dist/internal/extractor/adapters/python/scanner.d.ts +0 -18
- package/dist/internal/extractor/adapters/python/scanner.js +1 -54
- package/dist/internal/extractor/adapters/typescript/index.d.ts +0 -7
- package/dist/internal/extractor/adapters/typescript/index.js +1 -21
- package/dist/internal/extractor/adapters/typescript/manifest.d.ts +0 -14
- package/dist/internal/extractor/adapters/typescript/manifest.js +26 -17
- package/dist/internal/extractor/adapters/typescript/parser.d.ts +0 -8
- package/dist/internal/extractor/adapters/typescript/parser.js +0 -9
- package/dist/internal/extractor/adapters/typescript/scanner.d.ts +0 -24
- package/dist/internal/extractor/adapters/typescript/scanner.js +0 -43
- package/dist/internal/extractor/graph-builder.d.ts +10 -0
- package/dist/internal/extractor/graph-builder.js +245 -0
- package/dist/internal/extractor/graph-types.d.ts +89 -0
- package/dist/internal/extractor/graph-types.js +1 -0
- package/dist/internal/extractor/index.d.ts +0 -14
- package/dist/internal/extractor/index.js +0 -13
- package/dist/internal/extractor/types.d.ts +0 -45
- package/dist/internal/extractor/types.js +0 -27
- package/dist/internal/extractor/walker.d.ts +0 -18
- package/dist/internal/extractor/walker.js +0 -18
- package/dist/internal/gate-evaluate.d.ts +50 -0
- package/dist/internal/gate-evaluate.js +111 -0
- package/dist/internal/gate-policy.d.ts +38 -0
- package/dist/internal/gate-policy.js +167 -0
- package/dist/internal/git-metadata.d.ts +8 -0
- package/dist/internal/git-metadata.js +38 -0
- package/dist/internal/git.d.ts +9 -0
- package/dist/internal/git.js +45 -0
- package/dist/internal/github-linkage-prompt.d.ts +7 -0
- package/dist/internal/github-linkage-prompt.js +95 -0
- package/dist/internal/ide-setup.d.ts +17 -7
- package/dist/internal/ide-setup.js +379 -46
- package/dist/internal/inventory-sync.d.ts +74 -0
- package/dist/internal/inventory-sync.js +189 -0
- package/dist/internal/org-picker.d.ts +11 -0
- package/dist/internal/org-picker.js +34 -0
- package/dist/internal/orgs.js +0 -1
- package/dist/internal/packs/cache.d.ts +8 -0
- package/dist/internal/packs/cache.js +60 -0
- package/dist/internal/packs/index.d.ts +10 -0
- package/dist/internal/packs/index.js +8 -0
- package/dist/internal/packs/integrity.d.ts +9 -0
- package/dist/internal/packs/integrity.js +24 -0
- package/dist/internal/packs/jcs.d.ts +2 -0
- package/dist/internal/packs/jcs.js +57 -0
- package/dist/internal/packs/local-paths.d.ts +4 -0
- package/dist/internal/packs/local-paths.js +26 -0
- package/dist/internal/packs/npm-registry-client.d.ts +14 -0
- package/dist/internal/packs/npm-registry-client.js +87 -0
- package/dist/internal/packs/registry-client.d.ts +9 -0
- package/dist/internal/packs/registry-client.js +25 -0
- package/dist/internal/packs/resolve.d.ts +8 -0
- package/dist/internal/packs/resolve.js +89 -0
- package/dist/internal/packs/semver.d.ts +9 -0
- package/dist/internal/packs/semver.js +57 -0
- package/dist/internal/packs/signing.d.ts +5 -0
- package/dist/internal/packs/signing.js +56 -0
- package/dist/internal/packs/types.d.ts +77 -0
- package/dist/internal/packs/types.js +20 -0
- package/dist/internal/project-binding.d.ts +1 -0
- package/dist/internal/project-binding.js +16 -11
- package/dist/internal/resolve-init-session.d.ts +8 -0
- package/dist/internal/resolve-init-session.js +36 -0
- package/dist/internal/run-workdir.d.ts +2 -0
- package/dist/internal/run-workdir.js +19 -0
- package/dist/internal/security-context.d.ts +63 -0
- package/dist/internal/security-context.js +50 -0
- package/dist/internal/sync-outbox.d.ts +40 -0
- package/dist/internal/sync-outbox.js +66 -0
- package/dist/internal/target-auth/api-config.d.ts +0 -17
- package/dist/internal/target-auth/api-config.js +0 -18
- package/dist/internal/target-auth/config.d.ts +0 -12
- package/dist/internal/target-auth/config.js +0 -13
- package/dist/internal/target-auth/index.d.ts +0 -18
- package/dist/internal/target-auth/index.js +0 -19
- package/dist/internal/target-auth/keychain.d.ts +0 -18
- package/dist/internal/target-auth/keychain.js +3 -23
- package/dist/internal/target-auth/types.d.ts +0 -26
- package/dist/internal/target-auth/types.js +0 -10
- package/dist/internal/target-auth/workos.d.ts +0 -15
- package/dist/internal/target-auth/workos.js +9 -18
- package/dist/internal/test-scope.d.ts +99 -0
- package/dist/internal/test-scope.js +101 -0
- package/dist/internal/threatmodel-run-state.d.ts +15 -0
- package/dist/internal/threatmodel-run-state.js +43 -0
- package/dist/internal/threatmodel-run.d.ts +85 -0
- package/dist/internal/threatmodel-run.js +159 -0
- package/dist/internal/trust-room-link.d.ts +10 -0
- package/dist/internal/trust-room-link.js +15 -0
- package/dist/internal/zivis-local-state.d.ts +1 -0
- package/dist/internal/zivis-local-state.js +22 -0
- package/package.json +21 -5
- package/dist/commands/app/index.js.map +0 -1
- package/dist/commands/auth/index.js.map +0 -1
- package/dist/commands/auth/init.js.map +0 -1
- package/dist/commands/auth/login.js.map +0 -1
- package/dist/commands/auth/logout.js.map +0 -1
- package/dist/commands/auth/sessions.js.map +0 -1
- package/dist/commands/auth/status.js.map +0 -1
- package/dist/commands/credits/index.js.map +0 -1
- package/dist/commands/mcp/index.js.map +0 -1
- package/dist/commands/open/index.js.map +0 -1
- package/dist/commands/scan/index.js.map +0 -1
- package/dist/commands/target/index.js.map +0 -1
- package/dist/commands/tm/index.d.ts +0 -2
- package/dist/commands/tm/index.js +0 -266
- package/dist/commands/tm/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal/extractor/adapters/go/index.js.map +0 -1
- package/dist/internal/extractor/adapters/go/manifest.js.map +0 -1
- package/dist/internal/extractor/adapters/go/parser.js.map +0 -1
- package/dist/internal/extractor/adapters/go/scanner.js.map +0 -1
- package/dist/internal/extractor/adapters/python/index.js.map +0 -1
- package/dist/internal/extractor/adapters/python/manifest.js.map +0 -1
- package/dist/internal/extractor/adapters/python/parser.js.map +0 -1
- package/dist/internal/extractor/adapters/python/scanner.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/index.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/manifest.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/parser.js.map +0 -1
- package/dist/internal/extractor/adapters/typescript/scanner.js.map +0 -1
- package/dist/internal/extractor/index.js.map +0 -1
- package/dist/internal/extractor/types.js.map +0 -1
- package/dist/internal/extractor/walker.js.map +0 -1
- package/dist/internal/ide-setup.js.map +0 -1
- package/dist/internal/orgs.js.map +0 -1
- package/dist/internal/project-binding.js.map +0 -1
- package/dist/internal/target-auth/api-config.js.map +0 -1
- package/dist/internal/target-auth/config.js.map +0 -1
- package/dist/internal/target-auth/index.js.map +0 -1
- package/dist/internal/target-auth/keychain.js.map +0 -1
- package/dist/internal/target-auth/types.js.map +0 -1
- 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 {
|
|
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 {
|
|
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 {
|
|
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, "&")
|
|
60
|
+
.replace(/</g, "<")
|
|
61
|
+
.replace(/>/g, ">")
|
|
62
|
+
.replace(/"/g, """)
|
|
63
|
+
.replace(/'/g, "'");
|
|
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
|
+
}
|