@cantinasecurity/apex-cli 0.1.33 → 0.1.34
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 +1 -0
- 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/help.js +3 -3
- package/dist/onboarding-error-redaction.js +27 -0
- package/dist/onboarding.js +18 -3
- package/dist/redaction.js +14 -7
- package/package.json +1 -1
- package/skills/apex-cli/SKILL.md +1 -0
|
@@ -54,6 +54,7 @@ If the Apex MCP server is not configured, fall back to the local CLI:
|
|
|
54
54
|
- A trial redeem with an ambiguous transport or response-loss failure may be retried exactly once with the same code, machine, HOME, and repository root. Never retry a typed server rejection or use `--replace` for response-loss recovery.
|
|
55
55
|
- Guest standard scans validate the complete local archive before resolving or reserving a workspace. For an unbound renamed checkout, Apex may recover only the sole empty guest workspace when no explicit workspace name was supplied.
|
|
56
56
|
- 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.
|
|
57
|
+
- Shared Standard-scan codes may be custom names such as `TEST100` (1-64 letters, numbers, underscores, or hyphens). Use CLI 0.1.34 or newer. One redemption provides either a guest Standard scan or 100% off one 200-credit checkout package, sharing the same cap. Never redeem both paths with a one-use code. Legacy `APEX-...` and `SPBT-...` codes remain accepted. Do not repeat the real code in output.
|
|
57
58
|
- `apex-trial-status` is MCP-only; do not invoke it as a CLI command. In a CLI-only flow, use the `claimDeadline` returned by `apex redeem <code> --json` without repeating or persisting the secret code.
|
|
58
59
|
- After a guest scan, tell the user to run `apex claim` on the same machine before that returned claim deadline. If the deadline is unavailable or uncertain, do not guess or start a replacement login; run `apex claim` and let the server validate the proof.
|
|
59
60
|
- 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.
|
|
@@ -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.34"
|
|
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.34"
|
|
18
18
|
},
|
|
19
19
|
"description": "Run Apex security scans and review findings from Claude Code.",
|
|
20
|
-
"version": "0.1.
|
|
20
|
+
"version": "0.1.34",
|
|
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.34 apex-mcp
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
That keeps marketplace installs independent of a user's global `apex` install.
|
package/README.md
CHANGED
|
@@ -93,13 +93,19 @@ APEX_BASE_URL=https://bedrock.customer.example pnpm apex
|
|
|
93
93
|
|
|
94
94
|
## Try Apex With A Trial Code
|
|
95
95
|
|
|
96
|
+
Shared Standard-scan codes (including custom names such as `TEST100`) work with
|
|
97
|
+
Apex CLI 0.1.34 or newer. They provide either one guest Standard scan or 100% off
|
|
98
|
+
one 200-credit checkout package. Both paths share the code's redemption limit;
|
|
99
|
+
a one-use code cannot fund both. Previously issued `APEX-...` and `SPBT-...` codes
|
|
100
|
+
remain accepted. Code eligibility and remaining uses are checked by Bedrock.
|
|
101
|
+
|
|
96
102
|
A Cantina-issued trial code can start a temporary guest scan without a Cantina
|
|
97
103
|
account, browser, or device login. Redeem it from the repository root, run the
|
|
98
104
|
normal scan lifecycle, and create a Cantina account only after reviewing the
|
|
99
105
|
findings:
|
|
100
106
|
|
|
101
107
|
```bash
|
|
102
|
-
apex redeem
|
|
108
|
+
apex redeem <code> --json
|
|
103
109
|
apex scan --non-interactive --json
|
|
104
110
|
apex status --json
|
|
105
111
|
apex findings --json
|
|
@@ -152,30 +158,30 @@ unclaimed local trial proof so `apex claim` can still use it.
|
|
|
152
158
|
Agent-safe copy/paste prompt (substitute the issued code):
|
|
153
159
|
|
|
154
160
|
```text
|
|
155
|
-
Install and run Cantina Apex CLI 0.1.
|
|
161
|
+
Install and run Cantina Apex CLI 0.1.34 to start one free standard security scan of this repository immediately.
|
|
156
162
|
|
|
157
163
|
Use this trial code only where <TRIAL_CODE> appears below: SPBT-DEVREL-XXXXXXXX
|
|
158
164
|
|
|
159
165
|
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
166
|
|
|
161
167
|
Use this exact command prefix for every Apex command:
|
|
162
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
168
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.34 apex
|
|
163
169
|
|
|
164
170
|
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
171
|
2. Redeem, with at most one response-loss recovery retry:
|
|
166
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
172
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.34 apex redeem <TRIAL_CODE> --json
|
|
167
173
|
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
174
|
3. Immediately start exactly one scan; do not wait for another instruction:
|
|
169
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
175
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.34 apex scan --mode standard --non-interactive --no-open --json
|
|
170
176
|
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
177
|
4. About every 60 seconds, poll that exact scan:
|
|
172
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
178
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.34 apex status --scan <SCAN_ID> --json
|
|
173
179
|
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
180
|
5. Fetch that exact scan's findings:
|
|
175
|
-
npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
181
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.34 apex findings --scan <SCAN_ID> --json
|
|
176
182
|
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
183
|
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.
|
|
184
|
+
npx -y -p @cantinasecurity/apex-cli@0.1.34 apex claim
|
|
179
185
|
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
186
|
|
|
181
187
|
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.
|
|
@@ -657,7 +663,7 @@ Telemetry event posts do not include bearer tokens. The telemetry endpoint is `P
|
|
|
657
663
|
{
|
|
658
664
|
"schemaVersion": 1,
|
|
659
665
|
"event": "apex.invocation.completed",
|
|
660
|
-
"cliVersion": "0.1.
|
|
666
|
+
"cliVersion": "0.1.34",
|
|
661
667
|
"invocation": {
|
|
662
668
|
"surface": "mcp",
|
|
663
669
|
"command": "apex-scan",
|
|
@@ -688,7 +694,7 @@ The npm package also includes marketplace-ready plugin artifacts:
|
|
|
688
694
|
- `.claude-plugin/plugin.json` and `.mcp.claude.json` for Claude Code plugin installs
|
|
689
695
|
- `.claude-plugin/marketplace.json` for a Claude marketplace entry backed by the public npm package
|
|
690
696
|
|
|
691
|
-
These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.
|
|
697
|
+
These plugin installs launch the pinned npm package with `npx -y -p @cantinasecurity/apex-cli@0.1.34 apex-mcp`, so users do not need to install `apex` globally before enabling the plugin.
|
|
692
698
|
|
|
693
699
|
The repository also includes `.agents/plugins/marketplace.json` for local Codex marketplace testing from a checkout.
|
|
694
700
|
|
package/dist/help.js
CHANGED
|
@@ -25,7 +25,7 @@ export const CLI_HELP_TEXT = `Usage:
|
|
|
25
25
|
apex status Show progress for the latest or selected scan
|
|
26
26
|
apex doctor Validate auth, repos, connections, and workspace binding
|
|
27
27
|
apex login Sign in to Apex
|
|
28
|
-
apex redeem <
|
|
28
|
+
apex redeem <code> Redeem a Standard-scan code without device login
|
|
29
29
|
apex claim Link a guest workspace and findings to a Cantina account
|
|
30
30
|
apex logout Sign out locally
|
|
31
31
|
apex service-key create Create an organization service key (shown once)
|
|
@@ -183,8 +183,8 @@ Commands:
|
|
|
183
183
|
/exit Exit Apex
|
|
184
184
|
|
|
185
185
|
Scripted-only commands (run outside the interactive shell):
|
|
186
|
-
apex redeem <
|
|
187
|
-
|
|
186
|
+
apex redeem <code> [--json] [--replace]
|
|
187
|
+
Redeem a Standard-scan code without device login or browser access
|
|
188
188
|
apex service-key create --name <name> [--company <id-or-handle>] [--scope <scope[,scope]>]
|
|
189
189
|
Create an organization service key (shown once)
|
|
190
190
|
apex service-key list [--company <id-or-handle>]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { redactSensitiveText, redactSensitiveValue } from "./redaction.js";
|
|
2
|
+
// These top-level names describe the API error envelope, not user input.
|
|
3
|
+
const ONBOARDING_ERROR_FIELDS = new Set(["code", "error", "detail", "message"]);
|
|
4
|
+
// Public protocol enums are classification, never a free-form echo of the
|
|
5
|
+
// submitted code. Keep this allowlist aligned with Bedrock's onboarding errors.
|
|
6
|
+
const ONBOARDING_ERROR_CODES = new Set([
|
|
7
|
+
"INVALID_CODE_FORMAT", "INVALID_FINGERPRINT", "CODE_NOT_FOUND",
|
|
8
|
+
"CODE_EXPIRED", "CODE_REVOKED", "CODE_PAUSED", "CODE_EXHAUSTED",
|
|
9
|
+
"ACTIVE_GUEST_SESSION", "TRIAL_ALREADY_REDEEMED", "RATE_LIMITED",
|
|
10
|
+
"TRIAL_CAPACITY", "GUEST_SESSION_INVALID", "GUEST_SESSION_EXPIRED",
|
|
11
|
+
"GUEST_SESSION_CLAIMED", "GUEST_SESSION_REVOKED", "CLAIM_INVALID",
|
|
12
|
+
"CLAIM_EXPIRED", "ALREADY_CLAIMED", "FINGERPRINT_MISMATCH",
|
|
13
|
+
"CLAIM_PERSONAL_TENANT_EXISTS", "CLAIM_TARGET_UNAUTHORIZED",
|
|
14
|
+
"CLAIM_TARGET_PREFIX_EXHAUSTED", "CLAIM_SCAN_START_INDETERMINATE",
|
|
15
|
+
"CLAIM_RECONCILIATION_PENDING",
|
|
16
|
+
]);
|
|
17
|
+
export function redactOnboardingErrorBody(body, requestCode) {
|
|
18
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
19
|
+
return redactSensitiveValue(body, [requestCode]);
|
|
20
|
+
}
|
|
21
|
+
return Object.fromEntries(Object.entries(body).map(([key, value]) => [
|
|
22
|
+
ONBOARDING_ERROR_FIELDS.has(key) ? key : redactSensitiveText(key, [requestCode]),
|
|
23
|
+
key === "code" && typeof value === "string" && ONBOARDING_ERROR_CODES.has(value)
|
|
24
|
+
? value
|
|
25
|
+
: redactSensitiveValue(value, [requestCode]),
|
|
26
|
+
]));
|
|
27
|
+
}
|
package/dist/onboarding.js
CHANGED
|
@@ -3,9 +3,10 @@ import { loginWithoutPersist } from "./auth.js";
|
|
|
3
3
|
import { isClaimProofAvailable } from "./claim-proof.js";
|
|
4
4
|
import { ApiError, getApiErrorCode, redactSensitiveText, } from "./api-client.js";
|
|
5
5
|
import { clearCredentialsIfCurrent, clearGuestFieldsIfClaimTokenMatches, getOrCreateConfigString, loadConfig, loadCredentials, replaceCredentialsIfCurrent, updateConfig, withCredentialLifecycleLock, } from "./config.js";
|
|
6
|
+
import { redactOnboardingErrorBody } from "./onboarding-error-redaction.js";
|
|
6
7
|
import { APEX_CLI_VERSION } from "./version.js";
|
|
7
8
|
import { loadWorkspaceBinding, saveWorkspaceBinding } from "./workspace-binding.js";
|
|
8
|
-
const ONBOARDING_CODE_PATTERN = /^
|
|
9
|
+
const ONBOARDING_CODE_PATTERN = /^[A-Z0-9_-]{1,64}$/;
|
|
9
10
|
const ONBOARDING_FINGERPRINT_PATTERN = /^[a-f0-9]{64}$/;
|
|
10
11
|
const DEFAULT_CLIENT_NAME = "apex";
|
|
11
12
|
const HOSTED_APEX_ORIGIN = "https://ai.cantina.xyz";
|
|
@@ -541,8 +542,22 @@ async function redeemOnboardingCodeUnlocked(client, options = {}) {
|
|
|
541
542
|
: {}),
|
|
542
543
|
};
|
|
543
544
|
}
|
|
544
|
-
export function redeemOnboardingCode(client, options = {}) {
|
|
545
|
-
|
|
545
|
+
export async function redeemOnboardingCode(client, options = {}) {
|
|
546
|
+
const code = resolveOnboardingCode(options.code);
|
|
547
|
+
return withCredentialLifecycleLock(() => redeemOnboardingCodeUnlocked(client, { ...options, code })).catch((error) => {
|
|
548
|
+
// Custom codes have no recognizable prefix. Redact the exact request value
|
|
549
|
+
// at this boundary without retaining it in credentials or global state.
|
|
550
|
+
const message = redactSensitiveText(error instanceof Error ? error.message : String(error), [code]);
|
|
551
|
+
if (error instanceof ApiError) {
|
|
552
|
+
throw new ApiError(message, error.status, redactOnboardingErrorBody(error.body, code));
|
|
553
|
+
}
|
|
554
|
+
if (error instanceof AggregateError) {
|
|
555
|
+
throw new AggregateError(error.errors.map(e => new Error(redactSensitiveText(e instanceof Error ? e.message : String(e), [code]))), message);
|
|
556
|
+
}
|
|
557
|
+
// Rebuild ordinary errors so causes, stacks, and attached request fields
|
|
558
|
+
// cannot retain the custom code after its message has been sanitized.
|
|
559
|
+
throw new Error(message);
|
|
560
|
+
});
|
|
546
561
|
}
|
|
547
562
|
async function claimOnboardingSessionUnlocked(client, cwd, options = {}) {
|
|
548
563
|
let expectedCredentials = await loadCredentials();
|
package/dist/redaction.js
CHANGED
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
const APEX_SECRET_PATTERN = /(apex_(?:ct|at|rt|dc)_)[A-Za-z0-9._~+/=-]+/gi;
|
|
2
|
-
const ONBOARDING_CODE_PATTERN = /SPBT-[A-Z0-9]{2,24}-[A-Z0-9]{8}/gi;
|
|
2
|
+
const ONBOARDING_CODE_PATTERN = /(APEX|SPBT)-[A-Z0-9]{2,24}-[A-Z0-9]{8}/gi;
|
|
3
3
|
// Hex-only boundaries avoid redacting a 64-character window from a longer hex
|
|
4
4
|
// value while still catching fingerprints next to punctuation or prose.
|
|
5
5
|
const ONBOARDING_FINGERPRINT_PATTERN = /(?<![A-Fa-f0-9])[A-Fa-f0-9]{64}(?![A-Fa-f0-9])/g;
|
|
6
|
-
export function redactSensitiveText(value) {
|
|
7
|
-
|
|
6
|
+
export function redactSensitiveText(value, requestSecrets = []) {
|
|
7
|
+
let redacted = value;
|
|
8
|
+
for (const secret of requestSecrets) {
|
|
9
|
+
if (!secret)
|
|
10
|
+
continue;
|
|
11
|
+
const escaped = secret.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12
|
+
redacted = redacted.replace(new RegExp(`(?<![A-Z0-9_-])${escaped}(?![A-Z0-9_-])`, "gi"), "[REDACTED]");
|
|
13
|
+
}
|
|
14
|
+
return redacted
|
|
8
15
|
.replace(APEX_SECRET_PATTERN, (_match, prefix) => `${prefix}[REDACTED]`)
|
|
9
|
-
.replace(ONBOARDING_CODE_PATTERN,
|
|
16
|
+
.replace(ONBOARDING_CODE_PATTERN, (_match, prefix) => `${prefix.toUpperCase()}-[REDACTED]`)
|
|
10
17
|
.replace(ONBOARDING_FINGERPRINT_PATTERN, "[REDACTED]");
|
|
11
18
|
}
|
|
12
19
|
export function containsSensitiveText(value) {
|
|
13
20
|
return redactSensitiveText(value) !== value;
|
|
14
21
|
}
|
|
15
22
|
/** Redacts every string key and value in an API error body without mutating it. */
|
|
16
|
-
export function redactSensitiveValue(value) {
|
|
23
|
+
export function redactSensitiveValue(value, requestSecrets = []) {
|
|
17
24
|
const seen = new WeakSet();
|
|
18
25
|
const visit = (current) => {
|
|
19
26
|
if (typeof current === "string")
|
|
20
|
-
return redactSensitiveText(current);
|
|
27
|
+
return redactSensitiveText(current, requestSecrets);
|
|
21
28
|
if (!current || typeof current !== "object")
|
|
22
29
|
return current;
|
|
23
30
|
if (seen.has(current))
|
|
@@ -26,7 +33,7 @@ export function redactSensitiveValue(value) {
|
|
|
26
33
|
if (Array.isArray(current))
|
|
27
34
|
return current.map(visit);
|
|
28
35
|
return Object.fromEntries(Object.entries(current).map(([key, nested]) => [
|
|
29
|
-
redactSensitiveText(key),
|
|
36
|
+
redactSensitiveText(key, requestSecrets),
|
|
30
37
|
visit(nested),
|
|
31
38
|
]));
|
|
32
39
|
};
|
package/package.json
CHANGED
package/skills/apex-cli/SKILL.md
CHANGED
|
@@ -53,6 +53,7 @@ If the Apex MCP server is not configured, fall back to the local CLI:
|
|
|
53
53
|
- A trial redeem with an ambiguous transport or response-loss failure may be retried exactly once with the same code, machine, HOME, and repository root. Never retry a typed server rejection or use `--replace` for response-loss recovery.
|
|
54
54
|
- Guest standard scans validate the complete local archive before resolving or reserving a workspace. For an unbound renamed checkout, Apex may recover only the sole empty guest workspace when no explicit workspace name was supplied.
|
|
55
55
|
- 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.
|
|
56
|
+
- Shared Standard-scan codes may be custom names such as `TEST100` (1-64 letters, numbers, underscores, or hyphens). Use CLI 0.1.34 or newer. One redemption provides either a guest Standard scan or 100% off one 200-credit checkout package, sharing the same cap. Never redeem both paths with a one-use code. Legacy `APEX-...` and `SPBT-...` codes remain accepted. Do not repeat the real code in output.
|
|
56
57
|
- `apex-trial-status` is MCP-only; do not invoke it as a CLI command. In a CLI-only flow, use the `claimDeadline` returned by `apex redeem <code> --json` without repeating or persisting the secret code.
|
|
57
58
|
- After a guest scan, tell the user to run `apex claim` on the same machine before that returned claim deadline. If the deadline is unavailable or uncertain, do not guess or start a replacement login; run `apex claim` and let the server validate the proof.
|
|
58
59
|
- 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.
|