@cantinasecurity/apex-cli 0.1.25 → 0.1.26
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/.claude/skills/apex-cli/SKILL.md +2 -2
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.mcp.claude.json +1 -1
- package/.mcp.codex.json +1 -1
- package/MARKETPLACE.md +1 -1
- package/README.md +16 -10
- package/dist/apex.js +2 -1
- package/dist/args.js +50 -0
- package/dist/commands.js +9 -3
- package/dist/help.js +3 -1
- package/dist/service-key-environment.js +22 -0
- package/dist/telemetry.js +1 -35
- package/package.json +1 -1
- package/skills/apex-cli/SKILL.md +2 -2
|
@@ -57,8 +57,8 @@ If the Apex MCP server is not configured, fall back to the local CLI:
|
|
|
57
57
|
- Claim moves the guest workspace, scans, and findings into the currently selected Cantina workspace when the account can run scans there. Personal workspace owners receive the trial in their existing workspace instead of a duplicate. If the selected workspace cannot run scans, tell the user to switch to one that can and retry before the claim deadline.
|
|
58
58
|
- Service-key management has no MCP tools. Never ask a user to paste a service key into a prompt, and never place one in an MCP call, tool result, source file, or log.
|
|
59
59
|
- If a user explicitly needs a new service key, tell them to run `apex login` if needed, then run `apex service-key create --name <name> --scope <scope[,scope]>` directly in their own terminal. Use only the required scopes: `scans:create` to trigger, `scans:read` to poll status, and `findings:read` to retrieve findings. A P1-only adapter can use `--scope scans:read,findings:read`; omitting `--scope` grants all three. The CLI automatically selects the company when only one is available and prompts when there are several; use `--company <id-or-handle>` to skip that prompt or resolve a non-interactive command. Service-key commands never initiate login, and the secret is shown once.
|
|
60
|
-
- For a headless HTTP adapter, read the service key from
|
|
61
|
-
- Hosted API v1
|
|
60
|
+
- For a headless HTTP adapter, read the service key from the secret-backed `APEX_SERVICE_KEY` environment variable, send it as a bearer token to `/api/apex/v1`, and redact it from errors and logs. A service key does not authenticate CLI or MCP commands; those use device login. Do not shell out to `apex` or launch MCP from the adapter.
|
|
61
|
+
- Hosted API v1 remote-repository scans require the GitHub repository to be linked to an active Apex workspace and do not create or mutate workspaces; use optional `workspaceId` to disambiguate matches and treat zero or ambiguous matches as HTTP `409` setup errors. Local or non-Git scans use the documented source-upload flow, which can create or reuse a workspace; send `generateThreatModel: true` for the first scan of a newly created local workspace.
|
|
62
62
|
- Hosted scan triggers require `Idempotency-Key`. Reuse one stable key only for an identical transport/timeout/5xx retry. After correcting a definitive 4xx response, or for any new intended scan, use a new key.
|
|
63
63
|
- Use `--non-interactive` and `--no-open` for automation-friendly CLI calls.
|
|
64
64
|
- Use `--json` whenever structured output is helpful.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Cantina agent plugins for security review workflows.",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.26"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"source": {
|
|
15
15
|
"source": "npm",
|
|
16
16
|
"package": "@cantinasecurity/apex-cli",
|
|
17
|
-
"version": "0.1.
|
|
17
|
+
"version": "0.1.26"
|
|
18
18
|
},
|
|
19
19
|
"description": "Run Apex security scans and review findings from Claude Code.",
|
|
20
|
-
"version": "0.1.
|
|
20
|
+
"version": "0.1.26",
|
|
21
21
|
"author": {
|
|
22
22
|
"name": "Cantina",
|
|
23
23
|
"email": "support@cantina.xyz"
|
package/.mcp.claude.json
CHANGED
package/.mcp.codex.json
CHANGED
package/MARKETPLACE.md
CHANGED
|
@@ -13,7 +13,7 @@ This package is prepared as both a Claude Code plugin and a Codex plugin. The pu
|
|
|
13
13
|
The plugin MCP configs launch the pinned npm CLI package with:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
16
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex-mcp
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
That keeps marketplace installs independent of a user's global `apex` install.
|
package/README.md
CHANGED
|
@@ -152,30 +152,30 @@ unclaimed local trial proof so `apex claim` can still use it.
|
|
|
152
152
|
Agent-safe copy/paste prompt (substitute the issued code):
|
|
153
153
|
|
|
154
154
|
```text
|
|
155
|
-
Install and run Cantina Apex CLI 0.1.
|
|
155
|
+
Install and run Cantina Apex CLI 0.1.26 to start one free standard security scan of this repository immediately.
|
|
156
156
|
|
|
157
157
|
Use this trial code only where <TRIAL_CODE> appears below: SPBT-DEVREL-XXXXXXXX
|
|
158
158
|
|
|
159
159
|
Run the commands yourself from the repository root; do not stop after setup or only explain the steps. Use terminal CLI commands only. Do not use an Apex MCP tool or run `apex setup`, `apex mcp`, `apex login`, `apex-auth-start`, or `apex-auth-wait`. Never use `--replace` or `--force`.
|
|
160
160
|
|
|
161
161
|
Use this exact command prefix for every Apex command:
|
|
162
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
162
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex
|
|
163
163
|
|
|
164
164
|
1. Before redeeming, confirm every command will use the same persistent, user-accessible machine or container, HOME, filesystem, and repository root. Confirm Node.js 20+ and npx are available. If `APEX_BASE_URL` is set, continue only when its origin is `https://ai.cantina.xyz`. Run the exact prefix with `--help` and continue only if help lists both `redeem` and `claim`. If any check fails, STOP before sending the code; do not install system packages.
|
|
165
165
|
2. Redeem, with at most one response-loss recovery retry:
|
|
166
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
166
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex redeem <TRIAL_CODE> --json
|
|
167
167
|
This terminal command is the only allowed tool call containing the code. Never echo or restate the code, store it in a file or environment variable, put it in a URL or MCP call, or include it in your response. Parse the JSON from stdout only; do not merge stderr into stdout, because npm may write warnings to stderr. Continue when the command exits 0 and stdout is JSON with `redeemed: true` and `outcome` equal to `redeemed` or `idempotent`. `idempotent` means the existing guest session resumed and it may already own a workspace. If and only if the first attempt ends with an ambiguous transport/connection failure or an interrupted/missing response and no typed server error code, retry this exact same command once on the same machine, HOME, and repository root. Never retry a typed server rejection and never make more than one recovery retry. If the allowed retry does not return a successful JSON outcome, STOP.
|
|
168
168
|
3. Immediately start exactly one scan; do not wait for another instruction:
|
|
169
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
169
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex scan --mode standard --non-interactive --no-open --json
|
|
170
170
|
The CLI validates the complete guest local archive before it reserves a workspace. An unbound renamed checkout may recover only the sole empty guest workspace when no explicit workspace name was supplied. On any error or nonzero exit, STOP. After a successful scan JSON response, inspect `localPersistence.workspaceBindingSaved`. If it is `false`, the server scan already started: capture and report `binding.lastScanId`, then STOP; do not run status or findings until local repository permissions are repaired. Otherwise capture `binding.lastScanId` from the JSON as <SCAN_ID>; if it is absent, STOP.
|
|
171
171
|
4. About every 60 seconds, poll that exact scan:
|
|
172
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
172
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex status --scan <SCAN_ID> --json
|
|
173
173
|
Read `progress.progress.status`. Wait while it is `created`, `pending`, `queued`, `starting`, `running`, `in_progress`, or `processing`. Continue on `completed`. STOP on `failed`, `cancelled`, a missing or unknown status, or a command failure.
|
|
174
174
|
5. Fetch that exact scan's findings:
|
|
175
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
175
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex findings --scan <SCAN_ID> --json
|
|
176
176
|
On success, summarize findings by severity, most severe first, including identifier, title, status, and confidence. This command does not return file locations, so do not invent them. On failure, STOP.
|
|
177
177
|
6. Do not claim automatically. Tell me the claim deadline from step 2 and remind me to run this exact command myself from the same repository root, machine, and HOME:
|
|
178
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
178
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.26 apex claim
|
|
179
179
|
It may open a browser so I can create or sign in to a Cantina account and keep the results. Claim moves the trial into the currently selected Cantina workspace when I can run scans there, or into my existing personal workspace. If the selected workspace cannot run scans, tell me to switch to one that can and retry before the claim deadline.
|
|
180
180
|
|
|
181
181
|
Never paste raw command transcripts. For any failure, report only the step, exit code, and sanitized error. Redact the trial code and every `apex_at_`, `apex_rt_`, or `apex_ct_` value from all reports.
|
|
@@ -270,6 +270,8 @@ Supported shell commands:
|
|
|
270
270
|
- `apex connect github`
|
|
271
271
|
- `apex connect gitlab`
|
|
272
272
|
|
|
273
|
+
`--workspace-ref` is scoped to `apex findings --workspace`. For `apex scans` or `apex export findings`, bind the intended workspace first with `apex workspace use <name|prefix|id>`; unsupported or unknown flags fail instead of falling back to the local binding.
|
|
274
|
+
|
|
273
275
|
Helpful workspace flags:
|
|
274
276
|
|
|
275
277
|
- `--company <id-or-handle>` to choose the Apex company when more than one is available
|
|
@@ -307,6 +309,8 @@ apex service-key revoke <key-id>
|
|
|
307
309
|
|
|
308
310
|
Service-key management is intentionally available only through the scripted CLI. It is not exposed as an MCP tool or interactive-shell command, which keeps raw secrets out of model tool results and transcripts. The CLI requires an existing device-login bearer session, never initiates login from these commands, and never stores a created service key locally.
|
|
309
311
|
|
|
312
|
+
`APEX_SERVICE_KEY` authenticates the hosted REST API only; it does not authenticate CLI commands or replace `apex login`. When `apex doctor` finds a service key but no active device-login session, it reports that split before starting a login flow. `APEX_API_KEY` is also recognized for this diagnostic so older integrations receive migration guidance, but `APEX_SERVICE_KEY` is the documented REST variable.
|
|
313
|
+
|
|
310
314
|
Use the service key as a bearer token with the hosted scan lifecycle:
|
|
311
315
|
|
|
312
316
|
```bash
|
|
@@ -329,7 +333,9 @@ curl \
|
|
|
329
333
|
https://ai.cantina.xyz/api/apex/v1/scans/$SCAN_ID/findings
|
|
330
334
|
```
|
|
331
335
|
|
|
332
|
-
|
|
336
|
+
For a remote GitHub scan, the repository must already be linked to an active Apex workspace. This remote-repository flow never creates, binds, or mutates workspaces. Apex selects the workspace automatically when exactly one active workspace matches the repository; pass the optional `workspaceId` to disambiguate multiple matches. Zero matches, or multiple matches without a valid `workspaceId`, return HTTP `409`.
|
|
337
|
+
|
|
338
|
+
For a local or non-Git checkout, use the service API's source-upload flow instead. It can create or reuse a workspace, uploads a `tar.gz` archive, and starts the scan with a `local_archive` source. A newly created local workspace has no threat model to reuse, so its first scan must send `generateThreatModel: true`. See the [Apex service API guide](https://ai.cantina.xyz/docs/apex-api) for the current request schemas and limits.
|
|
333
339
|
|
|
334
340
|
The optional `paths` array is a set of best-effort focus hints, not a hard repository boundary. Apex may inspect or report code outside those paths. Version one does not yet provide strict path isolation.
|
|
335
341
|
|
|
@@ -576,7 +582,7 @@ Telemetry event posts do not include bearer tokens. The telemetry endpoint is `P
|
|
|
576
582
|
{
|
|
577
583
|
"schemaVersion": 1,
|
|
578
584
|
"event": "apex.invocation.completed",
|
|
579
|
-
"cliVersion": "0.1.
|
|
585
|
+
"cliVersion": "0.1.26",
|
|
580
586
|
"invocation": {
|
|
581
587
|
"surface": "mcp",
|
|
582
588
|
"command": "apex-scan",
|
|
@@ -607,7 +613,7 @@ The npm package also includes marketplace-ready plugin artifacts:
|
|
|
607
613
|
- `.claude-plugin/plugin.json` and `.mcp.claude.json` for Claude Code plugin installs
|
|
608
614
|
- `.claude-plugin/marketplace.json` for a Claude marketplace entry backed by the public npm package
|
|
609
615
|
|
|
610
|
-
These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
616
|
+
These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.26 apex-mcp`, so users do not need to install `apex` globally before enabling the plugin.
|
|
611
617
|
|
|
612
618
|
The repository also includes `.agents/plugins/marketplace.json` for local Codex marketplace testing from a checkout.
|
|
613
619
|
|
package/dist/apex.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApexApiClient, formatApiError } from "./api-client.js";
|
|
2
|
-
import { parseArgs } from "./args.js";
|
|
2
|
+
import { parseArgs, validateCommandFlags } from "./args.js";
|
|
3
3
|
import { commandCancelScan, commandClaim, commandConnect, commandCredits, commandDoctor, commandExportFindings, commandFindingComment, commandFindingFeedback, commandFindingFixReview, commandFindings, commandWorkspaceFindings, commandLogin, commandLogout, commandRedeem, commandScan, commandScans, commandServiceKeyCreate, commandServiceKeyList, commandServiceKeyRevoke, commandSetup, commandStatus, commandTelemetry, commandUpdate, commandWorkspace, commandWorkspaceUse, commandWorkspaces, getRedeemExitCode, } from "./commands.js";
|
|
4
4
|
import { CLI_HELP_TEXT } from "./help.js";
|
|
5
5
|
import { runMcpServer } from "./mcp.js";
|
|
@@ -154,6 +154,7 @@ async function dispatch(parsed) {
|
|
|
154
154
|
}
|
|
155
155
|
async function main() {
|
|
156
156
|
const parsed = parseArgs(process.argv.slice(2));
|
|
157
|
+
validateCommandFlags(parsed);
|
|
157
158
|
const invocation = createCliTelemetryInvocation(parsed);
|
|
158
159
|
emitInvocationStarted(invocation);
|
|
159
160
|
await withTelemetryContext(invocation, async () => {
|
package/dist/args.js
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
export const KNOWN_CLI_FLAG_NAMES = [
|
|
2
|
+
"comment",
|
|
3
|
+
"company",
|
|
4
|
+
"content",
|
|
5
|
+
"dismissal-reason",
|
|
6
|
+
"expires-at",
|
|
7
|
+
"fix-pr-url",
|
|
8
|
+
"force",
|
|
9
|
+
"format",
|
|
10
|
+
"filter",
|
|
11
|
+
"finding-state",
|
|
12
|
+
"help",
|
|
13
|
+
"json",
|
|
14
|
+
"label",
|
|
15
|
+
"limit",
|
|
16
|
+
"mode",
|
|
17
|
+
"name",
|
|
18
|
+
"no-open",
|
|
19
|
+
"non-interactive",
|
|
20
|
+
"output",
|
|
21
|
+
"parent-comment",
|
|
22
|
+
"pr",
|
|
23
|
+
"pr-path",
|
|
24
|
+
"replace",
|
|
25
|
+
"repo",
|
|
26
|
+
"review-target",
|
|
27
|
+
"scan",
|
|
28
|
+
"scope",
|
|
29
|
+
"source-mode",
|
|
30
|
+
"status",
|
|
31
|
+
"suggested-severity",
|
|
32
|
+
"workspace-name",
|
|
33
|
+
"workspace-ref",
|
|
34
|
+
"workspace",
|
|
35
|
+
];
|
|
36
|
+
const KNOWN_CLI_FLAGS = new Set(KNOWN_CLI_FLAG_NAMES);
|
|
1
37
|
const BOOLEAN_FLAGS = new Set([
|
|
2
38
|
"force",
|
|
3
39
|
"non-interactive",
|
|
@@ -25,6 +61,9 @@ export function parseArgs(argv) {
|
|
|
25
61
|
continue;
|
|
26
62
|
}
|
|
27
63
|
const key = value.slice(2);
|
|
64
|
+
if (!KNOWN_CLI_FLAGS.has(key)) {
|
|
65
|
+
throw new Error(`Unknown flag: --${key}`);
|
|
66
|
+
}
|
|
28
67
|
if (BOOLEAN_FLAGS.has(key)) {
|
|
29
68
|
flags[key] = true;
|
|
30
69
|
continue;
|
|
@@ -50,6 +89,17 @@ export function parseArgs(argv) {
|
|
|
50
89
|
flags,
|
|
51
90
|
};
|
|
52
91
|
}
|
|
92
|
+
export function validateCommandFlags(parsed) {
|
|
93
|
+
if (parsed.flags["workspace-ref"] === undefined) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const isWorkspaceFindings = parsed.command === "findings" &&
|
|
97
|
+
parsed.subcommand === null &&
|
|
98
|
+
parsed.flags.workspace === true;
|
|
99
|
+
if (!isWorkspaceFindings) {
|
|
100
|
+
throw new Error("--workspace-ref is only supported with `apex findings --workspace`. To change the local workspace used by scans or exports, run `apex workspace use <workspace-ref>` first.");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
53
103
|
export function isJsonMode(flags) {
|
|
54
104
|
return flags.json === true;
|
|
55
105
|
}
|
package/dist/commands.js
CHANGED
|
@@ -11,6 +11,7 @@ import { claimOnboardingSession, isProofOnlyOnboardingCredentials, redeemOnboard
|
|
|
11
11
|
import { confirm } from "./prompt.js";
|
|
12
12
|
import { cancelScan, fetchScanProgress, fetchWorkspaceScans, findMostRelevantActiveScan, getScanDisplayLabel, getScanDisplayId, getTrackedScanId, isActiveScanStatus, matchesScanId, selectDefaultScanToCancel, } from "./scan.js";
|
|
13
13
|
import { createServiceApiKey, isServiceApiScope, listServiceApiKeys, revokeServiceApiKey, SERVICE_API_SCOPES, } from "./service-keys.js";
|
|
14
|
+
import { getServiceKeyCliAuthGuidance } from "./service-key-environment.js";
|
|
14
15
|
import { chooseCompany, createWorkspaceBinding, ensureAuthenticated, planGuestWorkspaceSelection, remediateMissingConnections, resolveWorkspaceSelection, resolveWorkspaceSelectionLegacy, resolveWorkspaceAllowingMissingConnections, selectWorkspaceTarget, } from "./session.js";
|
|
15
16
|
import { createWorkspaceBindingFromSummary, fetchCompanyCredits, fetchCompanyWorkspaces, findWorkspaceByRef, } from "./workspaces.js";
|
|
16
17
|
import { loadWorkspaceBinding, saveWorkspaceBinding } from "./workspace-binding.js";
|
|
@@ -985,10 +986,15 @@ export async function commandTelemetry(flags, target) {
|
|
|
985
986
|
return payload;
|
|
986
987
|
}
|
|
987
988
|
export async function commandDoctor(client, cwd, flags) {
|
|
988
|
-
const me = await ensureAuthenticated(client, flags);
|
|
989
|
-
const authState = await getCommandAuthState(client, me);
|
|
990
|
-
setTelemetryAuthKind(authState.authKind);
|
|
991
989
|
try {
|
|
990
|
+
const serviceKeyGuidance = getServiceKeyCliAuthGuidance();
|
|
991
|
+
const existingMe = serviceKeyGuidance ? await getMe(client) : null;
|
|
992
|
+
if (serviceKeyGuidance && !existingMe) {
|
|
993
|
+
throw new Error(serviceKeyGuidance);
|
|
994
|
+
}
|
|
995
|
+
const me = existingMe ?? (await ensureAuthenticated(client, flags));
|
|
996
|
+
const authState = await getCommandAuthState(client, me);
|
|
997
|
+
setTelemetryAuthKind(authState.authKind);
|
|
992
998
|
const result = await withLoadingIndicator("Inspecting this directory and checking Apex setup...", flags, async () => {
|
|
993
999
|
if (authState.authKind === "guest") {
|
|
994
1000
|
const selection = await selectWorkspaceTarget(cwd, me, flags);
|
package/dist/help.js
CHANGED
|
@@ -43,7 +43,7 @@ Flags:
|
|
|
43
43
|
--workspace-name <name> Set the Apex workspace name for this directory
|
|
44
44
|
--scan <scan-id> Select a specific scan for status, findings, or export
|
|
45
45
|
--workspace Use the cross-scan workspace findings view
|
|
46
|
-
--workspace-ref <name|prefix|id> Select a workspace
|
|
46
|
+
--workspace-ref <name|prefix|id> Select a workspace for apex findings --workspace only
|
|
47
47
|
--finding-state all|open Select all findings or only findings needing review
|
|
48
48
|
--filter <[!]facet:value> Filter workspace findings; repeat for multiple filters
|
|
49
49
|
--status valid|invalid Set the finding feedback status explicitly
|
|
@@ -90,6 +90,7 @@ Tips:
|
|
|
90
90
|
After a guest scan, run apex claim on the same machine within the displayed claim deadline to keep the results.
|
|
91
91
|
Claim moves trial results into the selected Cantina workspace when you can run scans there, or into your existing personal workspace.
|
|
92
92
|
Service-key commands require an existing login; run apex login first when needed.
|
|
93
|
+
APEX_SERVICE_KEY authenticates the hosted REST API only; it does not replace apex login for CLI commands.
|
|
93
94
|
Apex automatically selects your company when only one is available. With multiple companies, choose one interactively or pass --company.
|
|
94
95
|
Service-key creation also requires --name and reveals the secret only once; omit --scope to grant all hosted API scopes.
|
|
95
96
|
Service-key management is available only in the scripted CLI, not the interactive shell or MCP server.
|
|
@@ -97,6 +98,7 @@ Tips:
|
|
|
97
98
|
Fix review scans use saved or supplied Fix PR URLs when present; otherwise they review the current repository when Bedrock has original scan repository context.
|
|
98
99
|
Finding identifiers such as KERN2-25 resolve against the selected scan; pass --scan or use the finding UUID directly when needed.
|
|
99
100
|
Use apex findings --workspace --company <handle> --workspace-ref <ref> --finding-state open to retrieve findings needing review without changing the local binding.
|
|
101
|
+
To run scans or exports against a different workspace, bind it first with apex workspace use <ref>.
|
|
100
102
|
Open excludes fixed, invalid, dismissed, and duplicate findings. It is a finding state, not a status filter.
|
|
101
103
|
Workspace filters match the web UI facets: severity, scan, repo, review, impact, likelihood, status, validation, visibility, duplicate, and source.
|
|
102
104
|
Anonymous usage telemetry helps Apex understand CLI, MCP, Codex, Claude, and Copilot usage. Disable it with apex telemetry disable or APEX_TELEMETRY_DISABLED=1.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const APEX_SERVICE_KEY_PREFIX = "apex_sk_";
|
|
2
|
+
export function detectApexServiceKeyEnvironment(env = process.env) {
|
|
3
|
+
for (const variableName of ["APEX_SERVICE_KEY", "APEX_API_KEY"]) {
|
|
4
|
+
const value = env[variableName]?.trim();
|
|
5
|
+
if (value?.startsWith(APEX_SERVICE_KEY_PREFIX)) {
|
|
6
|
+
return variableName;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
export function getServiceKeyCliAuthGuidance(env = process.env) {
|
|
12
|
+
const variableName = detectApexServiceKeyEnvironment(env);
|
|
13
|
+
if (!variableName) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const legacyVariableGuidance = variableName === "APEX_API_KEY"
|
|
17
|
+
? " For REST API examples, rename APEX_API_KEY to APEX_SERVICE_KEY."
|
|
18
|
+
: "";
|
|
19
|
+
return (`Apex service key detected in ${variableName}, but service keys authenticate the hosted REST API, not the Apex CLI. ` +
|
|
20
|
+
"Use `apex login` for CLI device authentication, or use the REST API for a headless/service-account integration: https://ai.cantina.xyz/docs/apex-api." +
|
|
21
|
+
legacyVariableGuidance);
|
|
22
|
+
}
|
package/dist/telemetry.js
CHANGED
|
@@ -2,6 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
2
2
|
import { execFileSync } from "node:child_process";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { KNOWN_CLI_FLAG_NAMES, } from "./args.js";
|
|
5
6
|
import { loadConfig, updateConfig } from "./config.js";
|
|
6
7
|
import { containsSensitiveText } from "./redaction.js";
|
|
7
8
|
import { APEX_CLI_VERSION } from "./version.js";
|
|
@@ -9,41 +10,6 @@ const TELEMETRY_ENDPOINT_PATH = "/api/cli/v1/telemetry/events";
|
|
|
9
10
|
const TELEMETRY_SESSION_ID = randomUUID();
|
|
10
11
|
const TELEMETRY_TIMEOUT_MS = 750;
|
|
11
12
|
const telemetryContext = new AsyncLocalStorage();
|
|
12
|
-
const KNOWN_CLI_FLAG_NAMES = [
|
|
13
|
-
"comment",
|
|
14
|
-
"company",
|
|
15
|
-
"content",
|
|
16
|
-
"dismissal-reason",
|
|
17
|
-
"expires-at",
|
|
18
|
-
"fix-pr-url",
|
|
19
|
-
"force",
|
|
20
|
-
"format",
|
|
21
|
-
"filter",
|
|
22
|
-
"finding-state",
|
|
23
|
-
"help",
|
|
24
|
-
"json",
|
|
25
|
-
"label",
|
|
26
|
-
"limit",
|
|
27
|
-
"mode",
|
|
28
|
-
"name",
|
|
29
|
-
"no-open",
|
|
30
|
-
"non-interactive",
|
|
31
|
-
"output",
|
|
32
|
-
"parent-comment",
|
|
33
|
-
"pr",
|
|
34
|
-
"pr-path",
|
|
35
|
-
"replace",
|
|
36
|
-
"repo",
|
|
37
|
-
"review-target",
|
|
38
|
-
"scan",
|
|
39
|
-
"scope",
|
|
40
|
-
"source-mode",
|
|
41
|
-
"status",
|
|
42
|
-
"suggested-severity",
|
|
43
|
-
"workspace-name",
|
|
44
|
-
"workspace-ref",
|
|
45
|
-
"workspace",
|
|
46
|
-
];
|
|
47
13
|
const KNOWN_CLI_COMMANDS = [
|
|
48
14
|
"cancel-scan",
|
|
49
15
|
"connect",
|
package/package.json
CHANGED
package/skills/apex-cli/SKILL.md
CHANGED
|
@@ -62,8 +62,8 @@ Guidelines:
|
|
|
62
62
|
- When MCP remains available after a guest scan, remind the user to run `apex claim` on the same machine while `claimAvailable` is true; after a known passed deadline, continue with normal account login.
|
|
63
63
|
- Service-key management has no MCP tools. Never ask a user to paste a service key into a prompt, and never place one in an MCP call, tool result, source file, or log.
|
|
64
64
|
- If a user explicitly needs a new service key, tell them to run `apex login` if needed, then run `apex service-key create --name <name> --scope <scope[,scope]>` directly in their own terminal. Use only the required scopes: `scans:create` to trigger, `scans:read` to poll status, and `findings:read` to retrieve findings. A P1-only adapter can use `--scope scans:read,findings:read`; omitting `--scope` grants all three. The CLI automatically selects the company when only one is available and prompts when there are several; use `--company <id-or-handle>` to skip that prompt or resolve a non-interactive command. Service-key commands never initiate login, and the secret is shown once.
|
|
65
|
-
- For a headless HTTP adapter, read the service key from
|
|
66
|
-
- Hosted API v1
|
|
65
|
+
- For a headless HTTP adapter, read the service key from the secret-backed `APEX_SERVICE_KEY` environment variable, send it as a bearer token to `/api/apex/v1`, and redact it from errors and logs. A service key does not authenticate CLI or MCP commands; those use device login. Do not shell out to `apex` or launch MCP from the adapter.
|
|
66
|
+
- Hosted API v1 remote-repository scans require the GitHub repository to be linked to an active Apex workspace and do not create or mutate workspaces; use optional `workspaceId` to disambiguate matches and treat zero or ambiguous matches as HTTP `409` setup errors. Local or non-Git scans use the documented source-upload flow, which can create or reuse a workspace; send `generateThreatModel: true` for the first scan of a newly created local workspace.
|
|
67
67
|
- Hosted scan triggers require `Idempotency-Key`. Reuse one stable key only for an identical transport/timeout/5xx retry. After correcting a definitive 4xx response, or for any new intended scan, use a new key.
|
|
68
68
|
- `apex-credits` reports standard credits plus audit, fix review, and Lite scan entitlements when Bedrock returns those balances.
|
|
69
69
|
- `apex-scan` scans the provided `cwd` by default; pass `repoPaths` only when the user asks to scan explicit alternate roots.
|