@zivis/cli 0.1.0-alpha.33 → 0.1.0-alpha.35
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 +0 -12
- package/dist/commands/auth/bind.d.ts +0 -10
- package/dist/commands/auth/bind.js +0 -11
- package/dist/commands/auth/index.js +0 -1
- package/dist/commands/auth/init.js +12 -13
- package/dist/commands/auth/login.d.ts +0 -1
- package/dist/commands/auth/login.js +8 -3
- package/dist/commands/auth/logout.js +0 -3
- package/dist/commands/auth/sessions.js +0 -1
- package/dist/commands/auth/status.js +0 -2
- package/dist/commands/auth/token.d.ts +0 -13
- package/dist/commands/auth/token.js +0 -18
- package/dist/commands/check/index.d.ts +2 -0
- package/dist/commands/check/index.js +463 -0
- package/dist/commands/credits/index.js +0 -1
- package/dist/commands/inspect/index.d.ts +0 -15
- package/dist/commands/inspect/index.js +0 -23
- package/dist/commands/mcp/index.js +0 -9
- package/dist/commands/open/index.d.ts +0 -8
- package/dist/commands/open/index.js +0 -11
- package/dist/commands/scan/index.js +0 -6
- package/dist/commands/target/index.js +0 -3
- package/dist/commands/tm/index.js +0 -7
- package/dist/index.js +11 -1
- package/dist/internal/binding-token-mint.d.ts +0 -29
- package/dist/internal/binding-token-mint.js +0 -28
- 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 +1 -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 +3 -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 +1 -20
- 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 +0 -25
- package/dist/internal/extractor/graph-builder.js +1 -39
- package/dist/internal/extractor/graph-types.d.ts +0 -10
- package/dist/internal/extractor/graph-types.js +0 -11
- 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/github-linkage-prompt.d.ts +7 -0
- package/dist/internal/github-linkage-prompt.js +95 -0
- package/dist/internal/ide-setup.d.ts +0 -23
- package/dist/internal/ide-setup.js +0 -53
- package/dist/internal/orgs.js +0 -1
- package/dist/internal/project-binding.d.ts +0 -1
- package/dist/internal/project-binding.js +0 -5
- 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 +0 -17
- package/package.json +13 -4
- package/dist/commands/app/index.js.map +0 -1
- package/dist/commands/auth/bind.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/auth/token.js.map +0 -1
- package/dist/commands/credits/index.js.map +0 -1
- package/dist/commands/inspect/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.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/internal/binding-token-mint.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/graph-builder.js.map +0 -1
- package/dist/internal/extractor/graph-types.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/pattern-pack/index.d.ts +0 -123
- package/dist/internal/pattern-pack/index.js +0 -230
- package/dist/internal/pattern-pack/index.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
- package/dist/pattern-packs/zivis-public-0.1.0/capsules/agents/privilege-separation.yaml +0 -228
- package/dist/pattern-packs/zivis-public-0.1.0/manifest.json +0 -31
- package/dist/pattern-packs/zivis-public-0.1.0/prompts/agents/privilege-separation/identify.md +0 -54
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extractor orchestrator.
|
|
3
|
-
*
|
|
4
|
-
* Walks the customer's repo, dispatches matched files to per-language
|
|
5
|
-
* adapters, merges their findings into a single ExtractionResult.
|
|
6
|
-
*
|
|
7
|
-
* Adapters register their own file extensions + manifest filenames; the
|
|
8
|
-
* walker only reads files those filters claim. So adding a Go or Python
|
|
9
|
-
* adapter doesn't change anything here — register the adapter and the
|
|
10
|
-
* orchestrator picks up its files.
|
|
11
|
-
*/
|
|
12
1
|
import * as path from "node:path";
|
|
13
2
|
import { walk } from "./walker.js";
|
|
14
3
|
import { typescriptAdapter } from "./adapters/typescript/index.js";
|
|
@@ -25,7 +14,6 @@ export async function runExtractor(opts) {
|
|
|
25
14
|
const adapters = opts.languages
|
|
26
15
|
? ADAPTERS.filter((a) => opts.languages.includes(a.language))
|
|
27
16
|
: ADAPTERS;
|
|
28
|
-
// Aggregate the file filters from each adapter so we walk the tree once.
|
|
29
17
|
const extensions = new Set();
|
|
30
18
|
const manifests = new Set();
|
|
31
19
|
for (const a of adapters) {
|
|
@@ -104,4 +92,3 @@ function dedupeExternalServices(items) {
|
|
|
104
92
|
}
|
|
105
93
|
return [...out.values()];
|
|
106
94
|
}
|
|
107
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extractor output schema.
|
|
3
|
-
*
|
|
4
|
-
* Matches `THREAT-MODEL-PHASE-J.md`'s J.2 output shape, with additions
|
|
5
|
-
* for privacy-audit metadata. The shape is the contract between the CLI
|
|
6
|
-
* and the eventual `--apply` endpoint that maps into ThreatModelComponent
|
|
7
|
-
* / OrgComponent records (RECON.3-gated).
|
|
8
|
-
*
|
|
9
|
-
* Privacy invariant — what's IN the JSON:
|
|
10
|
-
* component names ("auth-service")
|
|
11
|
-
* file paths ("src/auth/login.ts")
|
|
12
|
-
* line numbers (42)
|
|
13
|
-
* framework + SDK identifiers ("express", "@anthropic-ai/sdk")
|
|
14
|
-
* detected protocols / methods (POST /login)
|
|
15
|
-
* dependency versions (from package.json / go.mod / pyproject.toml)
|
|
16
|
-
*
|
|
17
|
-
* What's NOT:
|
|
18
|
-
* function bodies, file contents, code snippets
|
|
19
|
-
* variable names from inside functions
|
|
20
|
-
* comments
|
|
21
|
-
* raw AST nodes
|
|
22
|
-
*
|
|
23
|
-
* `zivis tm extract --privacy-audit` prints this whole object to stdout
|
|
24
|
-
* before any network call, so the customer can see exactly what would
|
|
25
|
-
* be sent.
|
|
26
|
-
*/
|
|
27
1
|
export type Language = "typescript" | "javascript" | "go" | "python";
|
|
28
2
|
export interface EvidenceLocation {
|
|
29
3
|
file: string;
|
|
@@ -44,21 +18,16 @@ export interface ConfigEvidence extends EvidenceLocation {
|
|
|
44
18
|
export type Evidence = HttpRouteEvidence | ImportEvidence | ConfigEvidence;
|
|
45
19
|
export type ComponentKind = "process" | "data_store" | "external_service" | "frontend";
|
|
46
20
|
export interface ExtractedComponent {
|
|
47
|
-
/** Stable name derived from path / module — never a value from inside a function. */
|
|
48
21
|
name: string;
|
|
49
22
|
kind: ComponentKind;
|
|
50
23
|
language: Language;
|
|
51
|
-
/** Detected web framework, if any (express | fastify | nextjs | trpc | hono | gin | echo | …). */
|
|
52
24
|
framework?: string;
|
|
53
25
|
sourceFiles: string[];
|
|
54
26
|
evidence: Evidence[];
|
|
55
27
|
}
|
|
56
28
|
export interface ExtractedExternalService {
|
|
57
|
-
/** Vendor / SDK name — "Anthropic", "OpenAI", "WorkOS". */
|
|
58
29
|
name: string;
|
|
59
|
-
/** What kind of integration: ai_sdk, payments, auth, observability, etc. */
|
|
60
30
|
kind: string;
|
|
61
|
-
/** npm/PyPI/Go module identifier ("@anthropic-ai/sdk"). */
|
|
62
31
|
package: string;
|
|
63
32
|
version?: string;
|
|
64
33
|
callSites: EvidenceLocation[];
|
|
@@ -84,30 +53,16 @@ export interface ExtractionResult {
|
|
|
84
53
|
components: ExtractedComponent[];
|
|
85
54
|
externalServices: ExtractedExternalService[];
|
|
86
55
|
dataStores: ExtractedDataStore[];
|
|
87
|
-
/**
|
|
88
|
-
* Per-language manifests detected in the scope. Surfaces dependency-only
|
|
89
|
-
* findings (e.g., "this repo uses @anthropic-ai/sdk@^0.30") even when
|
|
90
|
-
* we can't yet match call sites.
|
|
91
|
-
*/
|
|
92
56
|
manifests: ManifestSummary[];
|
|
93
57
|
}
|
|
94
58
|
export interface ManifestSummary {
|
|
95
59
|
language: Language;
|
|
96
60
|
file: string;
|
|
97
|
-
/** Direct dependency names → version (verbatim from manifest). */
|
|
98
61
|
dependencies: Record<string, string>;
|
|
99
62
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Adapter contract — one per language. Each adapter is fed the list of
|
|
102
|
-
* source files matched for it (already filtered by .gitignore + .zivisignore)
|
|
103
|
-
* plus any manifest files (package.json, go.mod, pyproject.toml). Returns
|
|
104
|
-
* structured findings the framework merges into the final ExtractionResult.
|
|
105
|
-
*/
|
|
106
63
|
export interface LanguageAdapter {
|
|
107
64
|
language: Language;
|
|
108
|
-
/** File extensions this adapter handles. */
|
|
109
65
|
extensions: string[];
|
|
110
|
-
/** Manifest filenames this adapter cares about. */
|
|
111
66
|
manifests: string[];
|
|
112
67
|
extract(input: AdapterInput): Promise<AdapterOutput>;
|
|
113
68
|
}
|
|
@@ -1,28 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extractor output schema.
|
|
3
|
-
*
|
|
4
|
-
* Matches `THREAT-MODEL-PHASE-J.md`'s J.2 output shape, with additions
|
|
5
|
-
* for privacy-audit metadata. The shape is the contract between the CLI
|
|
6
|
-
* and the eventual `--apply` endpoint that maps into ThreatModelComponent
|
|
7
|
-
* / OrgComponent records (RECON.3-gated).
|
|
8
|
-
*
|
|
9
|
-
* Privacy invariant — what's IN the JSON:
|
|
10
|
-
* component names ("auth-service")
|
|
11
|
-
* file paths ("src/auth/login.ts")
|
|
12
|
-
* line numbers (42)
|
|
13
|
-
* framework + SDK identifiers ("express", "@anthropic-ai/sdk")
|
|
14
|
-
* detected protocols / methods (POST /login)
|
|
15
|
-
* dependency versions (from package.json / go.mod / pyproject.toml)
|
|
16
|
-
*
|
|
17
|
-
* What's NOT:
|
|
18
|
-
* function bodies, file contents, code snippets
|
|
19
|
-
* variable names from inside functions
|
|
20
|
-
* comments
|
|
21
|
-
* raw AST nodes
|
|
22
|
-
*
|
|
23
|
-
* `zivis tm extract --privacy-audit` prints this whole object to stdout
|
|
24
|
-
* before any network call, so the customer can see exactly what would
|
|
25
|
-
* be sent.
|
|
26
|
-
*/
|
|
27
1
|
export {};
|
|
28
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1,24 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Filesystem walker — yields source files relative to the scan root,
|
|
3
|
-
* filtered by .gitignore + .zivisignore + per-extractor extension filters.
|
|
4
|
-
*
|
|
5
|
-
* Uses the `ignore` npm package (the same engine git ships with) so the
|
|
6
|
-
* matching semantics mirror what developers expect from .gitignore.
|
|
7
|
-
*
|
|
8
|
-
* Hard limits:
|
|
9
|
-
* - Skips node_modules, dist, build, .next, .git, .yarn, vendor — even
|
|
10
|
-
* if not in .gitignore. These exist by convention and contain
|
|
11
|
-
* third-party code that pollutes the inventory.
|
|
12
|
-
* - Caps total files at 50_000 to refuse to scan a generated monorepo
|
|
13
|
-
* by accident (extractor would take forever; user should narrow scope).
|
|
14
|
-
*/
|
|
15
1
|
export interface WalkOptions {
|
|
16
2
|
rootDir: string;
|
|
17
|
-
/** Extensions to include (with the leading dot, e.g. [".ts", ".tsx"]). */
|
|
18
3
|
extensions: string[];
|
|
19
|
-
/** Manifest basenames to capture regardless of extension (e.g. ["package.json"]). */
|
|
20
4
|
manifests: string[];
|
|
21
|
-
/** Extra ignore patterns from --ignore CLI flags. */
|
|
22
5
|
extraIgnores?: string[];
|
|
23
6
|
}
|
|
24
7
|
export interface WalkResult {
|
|
@@ -28,5 +11,4 @@ export interface WalkResult {
|
|
|
28
11
|
filesSkipped: number;
|
|
29
12
|
}
|
|
30
13
|
export declare function walk(opts: WalkOptions): Promise<WalkResult>;
|
|
31
|
-
/** Convert an absolute path to a posix-style repo-relative path. */
|
|
32
14
|
export declare function repoRelative(rootDir: string, absPath: string): string;
|
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Filesystem walker — yields source files relative to the scan root,
|
|
3
|
-
* filtered by .gitignore + .zivisignore + per-extractor extension filters.
|
|
4
|
-
*
|
|
5
|
-
* Uses the `ignore` npm package (the same engine git ships with) so the
|
|
6
|
-
* matching semantics mirror what developers expect from .gitignore.
|
|
7
|
-
*
|
|
8
|
-
* Hard limits:
|
|
9
|
-
* - Skips node_modules, dist, build, .next, .git, .yarn, vendor — even
|
|
10
|
-
* if not in .gitignore. These exist by convention and contain
|
|
11
|
-
* third-party code that pollutes the inventory.
|
|
12
|
-
* - Caps total files at 50_000 to refuse to scan a generated monorepo
|
|
13
|
-
* by accident (extractor would take forever; user should narrow scope).
|
|
14
|
-
*/
|
|
15
1
|
import * as fs from "node:fs/promises";
|
|
16
2
|
import * as path from "node:path";
|
|
17
3
|
import ignore from "ignore";
|
|
@@ -64,7 +50,6 @@ export async function walk(opts) {
|
|
|
64
50
|
filesSkipped++;
|
|
65
51
|
continue;
|
|
66
52
|
}
|
|
67
|
-
// ignore() expects gitignore-style paths with trailing /
|
|
68
53
|
if (ig.ignores(childRel + "/")) {
|
|
69
54
|
filesSkipped++;
|
|
70
55
|
continue;
|
|
@@ -99,12 +84,9 @@ async function loadIgnoreFile(ig, filePath) {
|
|
|
99
84
|
ig.add(content);
|
|
100
85
|
}
|
|
101
86
|
catch {
|
|
102
|
-
// No ignore file — fine.
|
|
103
87
|
}
|
|
104
88
|
}
|
|
105
|
-
/** Convert an absolute path to a posix-style repo-relative path. */
|
|
106
89
|
export function repoRelative(rootDir, absPath) {
|
|
107
90
|
const rel = path.relative(rootDir, absPath);
|
|
108
91
|
return rel.split(path.sep).join("/");
|
|
109
92
|
}
|
|
110
|
-
//# sourceMappingURL=walker.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ZivisConfig } from "@zivis/mcp/types";
|
|
2
|
+
export interface BuildLinkagePromptOpts {
|
|
3
|
+
config: ZivisConfig;
|
|
4
|
+
applicationId?: string;
|
|
5
|
+
style?: "short" | "full";
|
|
6
|
+
}
|
|
7
|
+
export declare function buildLinkagePrompt(opts: BuildLinkagePromptOpts): Promise<string | null>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { resolveAuth } from "@zivis/mcp/auth";
|
|
2
|
+
export async function buildLinkagePrompt(opts) {
|
|
3
|
+
const creds = await resolveAuth(opts.config);
|
|
4
|
+
if (creds.method === "none")
|
|
5
|
+
return null;
|
|
6
|
+
const appStatus = await fetchGitHubAppStatus(opts.config, creds);
|
|
7
|
+
if (!appStatus)
|
|
8
|
+
return null;
|
|
9
|
+
if (!appStatus.installed) {
|
|
10
|
+
if (!appStatus.installUrl)
|
|
11
|
+
return null;
|
|
12
|
+
return formatInstallPrompt(appStatus.installUrl, opts.style ?? "full");
|
|
13
|
+
}
|
|
14
|
+
if (opts.applicationId) {
|
|
15
|
+
const repoStatus = await fetchAppRepoStatus(opts.config, creds, opts.applicationId);
|
|
16
|
+
if (repoStatus && !repoStatus.linked) {
|
|
17
|
+
return formatLinkRepoPrompt(opts.config, opts.applicationId, opts.style ?? "full");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
async function fetchGitHubAppStatus(config, creds) {
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(`${config.apiBaseUrl}/api/github-app/status`, {
|
|
25
|
+
headers: authHeaders(creds),
|
|
26
|
+
});
|
|
27
|
+
if (!res.ok)
|
|
28
|
+
return null;
|
|
29
|
+
return (await res.json());
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function fetchAppRepoStatus(config, creds, applicationId) {
|
|
36
|
+
try {
|
|
37
|
+
const res = await fetch(`${config.apiBaseUrl}/api/applications/${encodeURIComponent(applicationId)}/repos/status`, { headers: authHeaders(creds) });
|
|
38
|
+
if (!res.ok)
|
|
39
|
+
return null;
|
|
40
|
+
return (await res.json());
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function authHeaders(creds) {
|
|
47
|
+
const base = {
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
"User-Agent": "@zivis/cli",
|
|
50
|
+
};
|
|
51
|
+
if (creds.method === "oauth" && creds.accessToken) {
|
|
52
|
+
base.Authorization = `Bearer ${creds.accessToken}`;
|
|
53
|
+
}
|
|
54
|
+
else if (creds.method === "apikey" && creds.apiKey) {
|
|
55
|
+
base["X-API-Key"] = creds.apiKey;
|
|
56
|
+
}
|
|
57
|
+
return base;
|
|
58
|
+
}
|
|
59
|
+
function formatInstallPrompt(installUrl, style) {
|
|
60
|
+
if (style === "short") {
|
|
61
|
+
return `Next: install the ZIVIS GitHub App — ${installUrl}`;
|
|
62
|
+
}
|
|
63
|
+
return [
|
|
64
|
+
"",
|
|
65
|
+
"Next: install the ZIVIS GitHub App",
|
|
66
|
+
` ${installUrl}`,
|
|
67
|
+
" Enables continuous monitoring + automatic threat-model updates on push.",
|
|
68
|
+
].join("\n");
|
|
69
|
+
}
|
|
70
|
+
function formatLinkRepoPrompt(config, applicationId, style) {
|
|
71
|
+
const appBase = process.env.ZIVIS_APP_URL || guessAppUrlFromApi(config.apiBaseUrl);
|
|
72
|
+
const url = `${appBase}/applications/${applicationId}`;
|
|
73
|
+
if (style === "short") {
|
|
74
|
+
return `Next: link a GitHub repo to this application — ${url}`;
|
|
75
|
+
}
|
|
76
|
+
return [
|
|
77
|
+
"",
|
|
78
|
+
"Next: link a GitHub repo to this application",
|
|
79
|
+
` ${url}`,
|
|
80
|
+
" The GitHub App is installed but this app has no linked repo yet.",
|
|
81
|
+
].join("\n");
|
|
82
|
+
}
|
|
83
|
+
function guessAppUrlFromApi(apiBaseUrl) {
|
|
84
|
+
try {
|
|
85
|
+
const u = new URL(apiBaseUrl);
|
|
86
|
+
if (u.host.startsWith("api.")) {
|
|
87
|
+
u.host = "app." + u.host.slice(4);
|
|
88
|
+
return `${u.protocol}//${u.host}`;
|
|
89
|
+
}
|
|
90
|
+
return apiBaseUrl;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return "https://app.zivis.ai";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -1,34 +1,11 @@
|
|
|
1
1
|
export type GuidanceClient = "cursor" | "claude-code-cli" | "vscode-copilot" | "vscode-claude" | "cline" | "windsurf";
|
|
2
2
|
export interface GuidanceOptions {
|
|
3
|
-
/** Workspace root to write guidance files into */
|
|
4
3
|
cwd: string;
|
|
5
|
-
/** Which IDE client to write guidance for */
|
|
6
4
|
client: GuidanceClient;
|
|
7
5
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Write IDE guidance files for the given client.
|
|
10
|
-
*
|
|
11
|
-
* The guidance files teach the host AI (Cursor, Claude Code, etc.)
|
|
12
|
-
* when to suggest ZIVIS tools — no security knowledge required from the user.
|
|
13
|
-
*
|
|
14
|
-
* All writes are idempotent: re-running replaces only the ZIVIS-managed
|
|
15
|
-
* block, never user content.
|
|
16
|
-
*
|
|
17
|
-
* Returns the list of file paths written.
|
|
18
|
-
*/
|
|
19
6
|
export declare function writeGuidance(opts: GuidanceOptions): string[];
|
|
20
|
-
/**
|
|
21
|
-
* Detect which IDE configs are present in the given workspace.
|
|
22
|
-
* Returns client identifiers whose config files/dirs were found.
|
|
23
|
-
*/
|
|
24
7
|
export declare function detectIdesInRepo(cwd: string): GuidanceClient[];
|
|
25
8
|
export declare function setupCursor(): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Write a workspace-level .cursor/mcp.json with `--workspace <cwd>` so Cursor
|
|
28
|
-
* starts an isolated MCP process bound to this specific repo.
|
|
29
|
-
* One process = one org = zero cross-tenant risk, regardless of what other
|
|
30
|
-
* repos are open in Cursor.
|
|
31
|
-
*/
|
|
32
9
|
export declare function setupCursorWorkspace(): Promise<void>;
|
|
33
10
|
export declare function setupVsCodeCopilot(): Promise<void>;
|
|
34
11
|
export declare function setupVsCodeClaude(): Promise<void>;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
const SERVER_NAME = "zivis";
|
|
4
|
-
// ── Idempotent block append ──
|
|
5
|
-
/**
|
|
6
|
-
* Append (or replace) a ZIVIS-managed block inside a text file.
|
|
7
|
-
* The block is wrapped in <!-- BEGIN ZIVIS:key --> / <!-- END ZIVIS:key -->
|
|
8
|
-
* markers so future calls replace only this section without touching user content.
|
|
9
|
-
*/
|
|
10
4
|
function appendBlock(filePath, blockKey, content) {
|
|
11
5
|
const begin = `<!-- BEGIN ZIVIS:${blockKey} -->`;
|
|
12
6
|
const end = `<!-- END ZIVIS:${blockKey} -->`;
|
|
@@ -31,8 +25,6 @@ function appendBlock(filePath, blockKey, content) {
|
|
|
31
25
|
function escapeRegex(s) {
|
|
32
26
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33
27
|
}
|
|
34
|
-
// ── Content templates ──
|
|
35
|
-
/** Full Cursor .mdc rule — uses globs so it only attaches when relevant files are open */
|
|
36
28
|
function cursorRuleContent() {
|
|
37
29
|
return `---
|
|
38
30
|
description: ZIVIS security guidance — quietly suggest security checks at the right moments
|
|
@@ -117,7 +109,6 @@ might break in", "security plan", "categories of attacks".
|
|
|
117
109
|
|
|
118
110
|
<!-- END ZIVIS:guidance -->`;
|
|
119
111
|
}
|
|
120
|
-
/** Short block for CLAUDE.md / AGENTS.md — must be concise (read every turn) */
|
|
121
112
|
function claudeBlockContent() {
|
|
122
113
|
return `## ZIVIS Security (MCP)
|
|
123
114
|
|
|
@@ -135,7 +126,6 @@ ZIVIS is connected to this project. Use its tools sparingly — only for securit
|
|
|
135
126
|
|
|
136
127
|
**Slash commands:** /zivis-getting-started /zivis-secure-my-app /zivis-audit-dependencies /zivis-prep-for-launch`;
|
|
137
128
|
}
|
|
138
|
-
/** .clinerules / .windsurfrules content */
|
|
139
129
|
function ruleFileContent() {
|
|
140
130
|
return `# ZIVIS Security Guidance
|
|
141
131
|
|
|
@@ -168,7 +158,6 @@ Say "security plan" not "threat model".
|
|
|
168
158
|
/zivis-prep-for-launch — pre-launch checklist
|
|
169
159
|
/zivis-weekly-check — weekly status update`;
|
|
170
160
|
}
|
|
171
|
-
/** GitHub Copilot instructions block */
|
|
172
161
|
function copilotBlockContent() {
|
|
173
162
|
return `## ZIVIS Security Integration
|
|
174
163
|
|
|
@@ -186,7 +175,6 @@ Use ZIVIS only for security-related user requests. Never proactively run scans o
|
|
|
186
175
|
|
|
187
176
|
**Language:** Avoid security jargon (threat model, STRIDE, attack vector) unless user uses it first.`;
|
|
188
177
|
}
|
|
189
|
-
// ── Per-IDE writers ──
|
|
190
178
|
function writeCursorGuidance(cwd) {
|
|
191
179
|
const rulesDir = path.join(cwd, ".cursor", "rules");
|
|
192
180
|
if (!fs.existsSync(rulesDir))
|
|
@@ -225,24 +213,12 @@ function writeWindsurfGuidance(cwd) {
|
|
|
225
213
|
fs.writeFileSync(rulesPath, ruleFileContent());
|
|
226
214
|
return rulesPath;
|
|
227
215
|
}
|
|
228
|
-
/**
|
|
229
|
-
* Write IDE guidance files for the given client.
|
|
230
|
-
*
|
|
231
|
-
* The guidance files teach the host AI (Cursor, Claude Code, etc.)
|
|
232
|
-
* when to suggest ZIVIS tools — no security knowledge required from the user.
|
|
233
|
-
*
|
|
234
|
-
* All writes are idempotent: re-running replaces only the ZIVIS-managed
|
|
235
|
-
* block, never user content.
|
|
236
|
-
*
|
|
237
|
-
* Returns the list of file paths written.
|
|
238
|
-
*/
|
|
239
216
|
export function writeGuidance(opts) {
|
|
240
217
|
const { cwd, client } = opts;
|
|
241
218
|
const written = [];
|
|
242
219
|
switch (client) {
|
|
243
220
|
case "cursor": {
|
|
244
221
|
written.push(writeCursorGuidance(cwd));
|
|
245
|
-
// Also write CLAUDE.md/AGENTS.md block if those files exist
|
|
246
222
|
const extraPaths = writeClaudeBlockGuidance(cwd).filter((p) => fs.existsSync(p));
|
|
247
223
|
written.push(...extraPaths);
|
|
248
224
|
break;
|
|
@@ -267,46 +243,25 @@ export function writeGuidance(opts) {
|
|
|
267
243
|
}
|
|
268
244
|
return written.filter(Boolean);
|
|
269
245
|
}
|
|
270
|
-
/**
|
|
271
|
-
* Detect which IDE configs are present in the given workspace.
|
|
272
|
-
* Returns client identifiers whose config files/dirs were found.
|
|
273
|
-
*/
|
|
274
246
|
export function detectIdesInRepo(cwd) {
|
|
275
247
|
const found = [];
|
|
276
|
-
// Cursor
|
|
277
248
|
if (fs.existsSync(path.join(cwd, ".cursor"))) {
|
|
278
249
|
found.push("cursor");
|
|
279
250
|
}
|
|
280
|
-
// Claude Code (CLAUDE.md)
|
|
281
251
|
if (fs.existsSync(path.join(cwd, "CLAUDE.md"))) {
|
|
282
252
|
found.push("claude-code-cli");
|
|
283
253
|
}
|
|
284
|
-
// VS Code (check for .vscode directory)
|
|
285
254
|
if (fs.existsSync(path.join(cwd, ".vscode"))) {
|
|
286
|
-
// Assume Copilot by default for VS Code
|
|
287
255
|
found.push("vscode-copilot");
|
|
288
256
|
}
|
|
289
|
-
// Cline (.clinerules)
|
|
290
257
|
if (fs.existsSync(path.join(cwd, ".clinerules"))) {
|
|
291
258
|
found.push("cline");
|
|
292
259
|
}
|
|
293
|
-
// Windsurf (.windsurfrules)
|
|
294
260
|
if (fs.existsSync(path.join(cwd, ".windsurfrules"))) {
|
|
295
261
|
found.push("windsurf");
|
|
296
262
|
}
|
|
297
263
|
return found;
|
|
298
264
|
}
|
|
299
|
-
/**
|
|
300
|
-
* Build the MCP server config for an IDE config file.
|
|
301
|
-
*
|
|
302
|
-
* When workspacePath is provided, we pass it as `--workspace <path>` so the
|
|
303
|
-
* MCP server process resolves its session from `.zivis/project.json` at that
|
|
304
|
-
* path — not from an env var that can drift or be accidentally reused across
|
|
305
|
-
* tenants. This gives us one-process-per-org isolation at the IDE level.
|
|
306
|
-
*
|
|
307
|
-
* ZIVIS_SESSION is intentionally NOT used here. The workspace path is the
|
|
308
|
-
* canonical, immutable tenant binding for an MCP process.
|
|
309
|
-
*/
|
|
310
265
|
function buildServerConfig(workspacePath, extra) {
|
|
311
266
|
const args = ["mcp", "serve"];
|
|
312
267
|
if (workspacePath) {
|
|
@@ -342,17 +297,10 @@ async function updateMcpConfig(configPath, serverName, serverConfig, rootKey) {
|
|
|
342
297
|
export async function setupCursor() {
|
|
343
298
|
const homeDir = process.env.HOME || "";
|
|
344
299
|
const configPath = path.join(homeDir, ".cursor", "mcp.json");
|
|
345
|
-
// Global config has no workspace path — serves repos without .zivis/project.json
|
|
346
300
|
await updateMcpConfig(configPath, SERVER_NAME, buildServerConfig(), "mcpServers");
|
|
347
301
|
console.log(`✓ Cursor global MCP config updated: ${configPath}`);
|
|
348
302
|
console.log(" Restart Cursor for changes to take effect");
|
|
349
303
|
}
|
|
350
|
-
/**
|
|
351
|
-
* Write a workspace-level .cursor/mcp.json with `--workspace <cwd>` so Cursor
|
|
352
|
-
* starts an isolated MCP process bound to this specific repo.
|
|
353
|
-
* One process = one org = zero cross-tenant risk, regardless of what other
|
|
354
|
-
* repos are open in Cursor.
|
|
355
|
-
*/
|
|
356
304
|
export async function setupCursorWorkspace() {
|
|
357
305
|
const workspacePath = process.cwd();
|
|
358
306
|
const configPath = path.join(workspacePath, ".cursor", "mcp.json");
|
|
@@ -446,4 +394,3 @@ export function printClaudeCodeManual() {
|
|
|
446
394
|
console.log("");
|
|
447
395
|
console.log("Then restart Claude Code for changes to take effect");
|
|
448
396
|
}
|
|
449
|
-
//# sourceMappingURL=ide-setup.js.map
|
package/dist/internal/orgs.js
CHANGED
|
@@ -7,7 +7,6 @@ export interface EnsureBindingOpts {
|
|
|
7
7
|
cwd: string;
|
|
8
8
|
autoBind: boolean;
|
|
9
9
|
skipBind: boolean;
|
|
10
|
-
/** Overwrite an existing conflicting binding without erroring (used by `zivis auth init`). */
|
|
11
10
|
force?: boolean;
|
|
12
11
|
}
|
|
13
12
|
export declare function ensureProjectBinding(opts: EnsureBindingOpts): Promise<void>;
|
|
@@ -28,8 +28,6 @@ export async function ensureProjectBinding(opts) {
|
|
|
28
28
|
console.error("[zivis] This should not happen — investigate before proceeding.");
|
|
29
29
|
process.exit(1);
|
|
30
30
|
}
|
|
31
|
-
// force=true: init is intentionally replacing the binding.
|
|
32
|
-
// Clear detected so we don't accidentally inherit the OLD binding's name/id.
|
|
33
31
|
const oldLabel = detected.binding.orgName ?? detected.binding.workosOrgId;
|
|
34
32
|
console.log(` Replacing existing binding (was: ${oldLabel})`);
|
|
35
33
|
fs.unlinkSync(detected.filePath);
|
|
@@ -43,8 +41,6 @@ export async function ensureProjectBinding(opts) {
|
|
|
43
41
|
catch (err) {
|
|
44
42
|
console.log(` WARNING: Could not fetch org info: ${err instanceof Error ? err.message : err}`);
|
|
45
43
|
}
|
|
46
|
-
// Only fall back to detected?.binding.orgName when we are UPGRADING the same org
|
|
47
|
-
// (detected still set), not when force-replacing a different org (detected=null).
|
|
48
44
|
const orgName = orgInfo?.name || detected?.binding.orgName;
|
|
49
45
|
const zivisOrgId = orgInfo?.id || detected?.binding.orgId;
|
|
50
46
|
const orgLabel = orgName ? `${orgName} (${jwtOrgId})` : jwtOrgId;
|
|
@@ -103,4 +99,3 @@ export async function ensureProjectBinding(opts) {
|
|
|
103
99
|
console.log(` File: ${bindingPath}`);
|
|
104
100
|
console.log(" Commit this file so future sessions in this repo are org-locked.");
|
|
105
101
|
}
|
|
106
|
-
//# sourceMappingURL=project-binding.js.map
|
|
@@ -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>;
|