instabox 0.6.3 → 0.7.0
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/README.md +3 -3
- package/bin/instabox.mjs +23 -102
- package/lib/cli.mjs +1 -1
- package/lib/login.mjs +37 -36
- package/package.json +1 -1
- package/skills/instabox/SKILL.md +33 -27
- package/skills/instabox-basic-setup/SKILL.md +16 -23
- package/skills/instabox-basic-setup/scripts/content.mjs +6 -22
- package/skills/instabox-basic-setup/scripts/lib.mjs +49 -68
- package/skills/instabox-basic-setup/scripts/plan.mjs +17 -48
- package/skills/instabox-basic-setup/scripts/push.mjs +29 -32
- package/skills/instabox-basic-setup/scripts/scan.mjs +41 -32
- package/skills/instabox-move-repo/SKILL.md +7 -30
- package/skills/instabox-move-repo/scripts/deps.sh +1 -1
- package/skills/instabox-move-repo/scripts/repo-files.mjs +2 -2
- package/skills/instabox-snapshots/SKILL.md +4 -4
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
MACOS_ONLY,
|
|
14
14
|
SECRET_VALUE,
|
|
15
15
|
FILE_MAX_VALUE,
|
|
16
|
-
|
|
16
|
+
FORMAT,
|
|
17
|
+
TOKEN_HOSTS,
|
|
17
18
|
hasCommand,
|
|
18
19
|
isMain,
|
|
19
20
|
isSecretName,
|
|
@@ -76,7 +77,6 @@ function scanTokens({ home, env, procEnv }) {
|
|
|
76
77
|
byName.set(name, item);
|
|
77
78
|
items.push(item);
|
|
78
79
|
};
|
|
79
|
-
const reserved = new Set();
|
|
80
80
|
|
|
81
81
|
// gh: the token gh keeps (keychain or hosts.yml), read with `gh auth token` at push time.
|
|
82
82
|
if (hasCommand('gh', env)) {
|
|
@@ -84,42 +84,54 @@ function scanTokens({ home, env, procEnv }) {
|
|
|
84
84
|
if (st.ok) {
|
|
85
85
|
const who = (st.stdout + st.stderr).match(/account (\S+)/)?.[1] || null;
|
|
86
86
|
add('GH_TOKEN', { type: 'cmd', argv: ['gh', 'auth', 'token', '--hostname', 'github.com'] }, '`gh auth token`', {
|
|
87
|
-
note: `${who ? `GitHub account ${who}; ` : ''}gh
|
|
87
|
+
note: `${who ? `GitHub account ${who}; ` : ''}gh uses it on the box; git over HTTPS needs its own sign-in`,
|
|
88
88
|
});
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
// Shell startup files: exported tokens.
|
|
92
|
+
// Shell startup files: exported tokens. Only names in TOKEN_HOSTS can be saved; any other
|
|
93
|
+
// credential-looking export is a manual step.
|
|
94
|
+
const listed = new Set();
|
|
95
|
+
const listManual = (name, place, why, todo) => {
|
|
96
|
+
if (listed.has(name)) return;
|
|
97
|
+
listed.add(name);
|
|
98
|
+
manual.push({ what: `${name} (${place})`, why, todo });
|
|
99
|
+
};
|
|
93
100
|
for (const f of SHELL_RC) {
|
|
94
101
|
const text = readText(join(home, f));
|
|
95
102
|
if (text === null) continue;
|
|
96
103
|
for (const a of shellAssignments(text)) {
|
|
97
|
-
if (!
|
|
104
|
+
if (!TOKEN_HOSTS.has(a.name) && !isSecretName(a.name) && !a.secretValue) continue;
|
|
105
|
+
const place = `~/${f}:${a.line}`;
|
|
98
106
|
if (!secretNameOK(a.name)) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
listManual(
|
|
108
|
+
a.name,
|
|
109
|
+
place,
|
|
110
|
+
'Secrets reserve this variable name for sandbox or trust configuration',
|
|
111
|
+
'if a box needs it, set it there by hand',
|
|
112
|
+
);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (!TOKEN_HOSTS.has(a.name)) {
|
|
116
|
+
listManual(
|
|
117
|
+
a.name,
|
|
118
|
+
place,
|
|
119
|
+
'this skill does not know which HTTPS API hosts it is for',
|
|
120
|
+
`if its client sends it in an HTTPS header, \`instabox secrets set ${a.name} --org <org> --host <api-host>\` and select it on the box; other credentials need their own setup there`,
|
|
121
|
+
);
|
|
107
122
|
continue;
|
|
108
123
|
}
|
|
109
124
|
const extra = {};
|
|
110
125
|
if (a.keychain) {
|
|
111
126
|
extra.checked = false;
|
|
112
127
|
extra.reason = 'your shell reads it from the macOS keychain: checking it runs that lookup once, at push time';
|
|
113
|
-
} else if (!WELL_KNOWN.has(a.name)) {
|
|
114
|
-
extra.checked = false;
|
|
115
|
-
extra.reason = 'not a well-known model or service token: check it only for the org and sandboxes in the plan';
|
|
116
128
|
}
|
|
117
|
-
add(a.name, { type: 'rc', file: join(home, f), name: a.name },
|
|
129
|
+
add(a.name, { type: 'rc', file: join(home, f), name: a.name }, place, extra);
|
|
118
130
|
}
|
|
119
131
|
}
|
|
120
|
-
//
|
|
132
|
+
// Known tokens in the environment the scan runs in (set some other way than a shell file).
|
|
121
133
|
for (const name of Object.keys(procEnv).sort()) {
|
|
122
|
-
if (!
|
|
134
|
+
if (!TOKEN_HOSTS.has(name) || !procEnv[name]) continue;
|
|
123
135
|
add(name, { type: 'env', name }, 'this shell’s environment');
|
|
124
136
|
}
|
|
125
137
|
|
|
@@ -127,23 +139,20 @@ function scanTokens({ home, env, procEnv }) {
|
|
|
127
139
|
manual.push({
|
|
128
140
|
what: 'GitHub token (GH_TOKEN)',
|
|
129
141
|
why: hasCommand('gh', env) ? 'gh is not signed in on this machine' : 'gh is not installed on this machine',
|
|
130
|
-
todo: 'sign in here with `gh auth login` and run this again; or put a token in yourself: `instabox secrets set GH_TOKEN --org <org> --
|
|
131
|
-
});
|
|
132
|
-
if (!byName.has('CLAUDE_CODE_OAUTH_TOKEN'))
|
|
133
|
-
manual.push({
|
|
134
|
-
what: 'Claude Code sign-in (CLAUDE_CODE_OAUTH_TOKEN)',
|
|
135
|
-
why: 'not found in your shell files; the sign-in on this machine is in the macOS keychain, and is never read',
|
|
136
|
-
todo:
|
|
137
|
-
'run `claude setup-token` yourself, then `instabox secrets set CLAUDE_CODE_OAUTH_TOKEN --org <org> --delivery env` and paste it at the prompt' +
|
|
138
|
-
(byName.has('ANTHROPIC_API_KEY')
|
|
139
|
-
? ' (or skip it: ANTHROPIC_API_KEY is in the plan, and Claude Code uses that)'
|
|
140
|
-
: '; or `claude`, then /login, on each box'),
|
|
142
|
+
todo: 'sign in here with `gh auth login` and run this again; or put a token in yourself: `instabox secrets set GH_TOKEN --org <org> --host api.github.com` (it prompts without echo)',
|
|
141
143
|
});
|
|
144
|
+
manual.push({
|
|
145
|
+
what: 'Claude Code sign-in',
|
|
146
|
+
why: 'the sign-in on this machine is in the macOS keychain, and is never read',
|
|
147
|
+
todo: byName.has('ANTHROPIC_API_KEY')
|
|
148
|
+
? 'skip it: ANTHROPIC_API_KEY is in the plan, and Claude Code uses that; or run `claude`, then /login, on each box'
|
|
149
|
+
: 'run `claude`, then /login, on each box',
|
|
150
|
+
});
|
|
142
151
|
if (!byName.has('OPENAI_API_KEY') && (hasCommand('codex', env) || statOrNull(join(home, '.codex'))))
|
|
143
152
|
manual.push({
|
|
144
153
|
what: 'Codex sign-in',
|
|
145
154
|
why: 'no OPENAI_API_KEY in your shell files; a ChatGPT sign-in cannot be copied (its refresh token rotates)',
|
|
146
|
-
todo: 'on each box: `codex login --device-auth`; or `instabox secrets set OPENAI_API_KEY --org <org> --
|
|
155
|
+
todo: 'on each box: `codex login --device-auth`; or `instabox secrets set OPENAI_API_KEY --org <org> --host api.openai.com`, then select it on each box',
|
|
147
156
|
});
|
|
148
157
|
return { items, manual };
|
|
149
158
|
}
|
|
@@ -259,7 +268,7 @@ export function scan(opts = {}) {
|
|
|
259
268
|
const home = resolve(opts.home || env.HOME);
|
|
260
269
|
const tokens = scanTokens({ home, env, procEnv: opts.procEnv || env });
|
|
261
270
|
const items = [...tokens.items, ...scanGit({ home, env }), ...scanEditor({ home })];
|
|
262
|
-
return { version:
|
|
271
|
+
return { version: FORMAT, home, platform: opts.platform || process.platform, items, manual: tokens.manual };
|
|
263
272
|
}
|
|
264
273
|
|
|
265
274
|
function main() {
|
|
@@ -20,16 +20,16 @@ Three scripts in `scripts/` next to this file do the parts that must be exact (N
|
|
|
20
20
|
What goes over:
|
|
21
21
|
|
|
22
22
|
- All of the main checkout's `.git` (branches, tags, stashes, unpushed commits, the index so staged changes stay staged, each worktree's own HEAD and index), every tracked file, and every untracked file git does not ignore, in the main checkout and in each linked worktree.
|
|
23
|
-
- **Never build output or dependencies**, even when the repo forgot to ignore them: `node_modules`, `target`, `dist`, `build`, `out`, `.next`, `.nuxt`, `.svelte-kit`, `.turbo`, `.cache`, `coverage`, `__pycache__`, `.venv`, `venv`, `.tox`, `.mypy_cache`, `.pytest_cache`, `.gradle`, `bazel-*`, `*.egg-info`, `*.o`, `*.so`, `*.pyc`, `*.class`, ... (the full list is `EXCLUDED_DIRS` and `EXCLUDED_FILES` in `repo-files.mjs`). Files git ignores stay too. A **tracked** file always goes, even under such a name, so `git status` matches. `--keep NAME` copies an excluded name anyway, for a repo whose source really lives in, say, `build/` (pass it to every `repo-files.mjs` run, step 1 and step 3, through `KEEP`). It does not bring back an untracked `.env`:
|
|
23
|
+
- **Never build output or dependencies**, even when the repo forgot to ignore them: `node_modules`, `target`, `dist`, `build`, `out`, `.next`, `.nuxt`, `.svelte-kit`, `.turbo`, `.cache`, `coverage`, `__pycache__`, `.venv`, `venv`, `.tox`, `.mypy_cache`, `.pytest_cache`, `.gradle`, `bazel-*`, `*.egg-info`, `*.o`, `*.so`, `*.pyc`, `*.class`, ... (the full list is `EXCLUDED_DIRS` and `EXCLUDED_FILES` in `repo-files.mjs`). Files git ignores stay too. A **tracked** file always goes, even under such a name, so `git status` matches. `--keep NAME` copies an excluded name anyway, for a repo whose source really lives in, say, `build/` (pass it to every `repo-files.mjs` run, step 1 and step 3, through `KEEP`). It does not bring back an untracked `.env`: those stay behind (step 7 lists them).
|
|
24
24
|
- Claude Code and Codex conversations for the repo and its worktrees (on by default, the user can opt out).
|
|
25
25
|
|
|
26
|
-
Not moved: `.env` files that are not committed
|
|
26
|
+
Not moved: `.env` files that are not committed, credentials stored outside the repo (git credential helpers, gh, cloud, API keys in your environment), other local tools and config, other repos. A `.env` that is committed or staged is in `.git` and goes with it. Everything inside `.git` goes, including `.git/config` and so a remote URL with a token embedded in it (`https://x-access-token:TOKEN@...`); and only `.env`-named untracked files are held back, so an untracked `.npmrc` with a token, a `*.pem` or a `secrets.yaml` that git does not ignore goes too.
|
|
27
27
|
|
|
28
28
|
**Never read, print or paste a credential value yourself**: not a `.env`, not `gh auth token`, not `echo $SOME_KEY`.
|
|
29
29
|
|
|
30
30
|
Before starting, tell the user plainly:
|
|
31
31
|
|
|
32
|
-
- **git push/pull from the box will not work until they set up credentials there** (for example `instabox ssh <box>` then `gh auth login`; org Secrets
|
|
32
|
+
- **git push/pull from the box will not work until they set up credentials there** (for example `instabox ssh <box>` then `gh auth login`; org Secrets cover HTTP API keys only, so git sign-in is set up separately).
|
|
33
33
|
- **The copied conversation history may contain secrets they pasted earlier** (tokens, keys, passwords). It goes by default; ask whether to skip it (or only Codex / only Claude Code).
|
|
34
34
|
- Their local copy stays as it is, and nothing keeps the two in sync afterwards.
|
|
35
35
|
|
|
@@ -72,7 +72,7 @@ BOX=<box>
|
|
|
72
72
|
instabox create --name "$BOX" --meta repo="$(basename "$DEST")"
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
Box names are lowercase letters, digits and `-`. The box gets the default size, 4 vCPU / 8 GB (the instabox skill's Sizes lists the others a plan offers). The default template (`agent-browser`, shown as standard in the dashboard) has git, Node.js 22, Python (uv), Go, Rust, a C toolchain, Docker and a desktop with Chromium. This box is meant to stay; it pauses itself after 30 idle minutes. The `repo=` label can match existing Vault selectors; it does not select org Secrets. Without
|
|
75
|
+
Box names are lowercase letters, digits and `-`. The box gets the default size, 4 vCPU / 8 GB (the instabox skill's Sizes lists the others a plan offers). The default template (`agent-browser`, shown as standard in the dashboard) has git, Node.js 22, Python (uv), Go, Rust, a C toolchain, Docker and a desktop with Chromium. This box is meant to stay; it pauses itself after 30 idle minutes. The `repo=` label can match a user's existing Vault selectors (the Vault is legacy and will be retired; never save credentials there); it does not select org Secrets. Without `--secrets` the box still gets such existing Vault items. Opt into org Secrets explicitly with `--secrets NAME,NAME`. Use `--no-vault --secrets none` when neither store should deliver credentials.
|
|
76
76
|
|
|
77
77
|
## 3. Copy the repo and its worktrees
|
|
78
78
|
|
|
@@ -111,7 +111,7 @@ done
|
|
|
111
111
|
git worktree list; instabox exec "$BOX" --cwd "$DEST" -- git worktree list
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
The only allowed differences are `<` lines starting with `??` for what the plan left out (a build directory, an untracked `.env`, or a whole `?? dir/` that held only those), and ` M <submodule>` for a submodule with uncommitted changes inside it (those are not copied: note it for step
|
|
114
|
+
The only allowed differences are `<` lines starting with `??` for what the plan left out (a build directory, an untracked `.env`, or a whole `?? dir/` that held only those), and ` M <submodule>` for a submodule with uncommitted changes inside it (those are not copied: note it for step 7). A name passed with `--keep` must not show up as a `??` difference: it was meant to go. HEADs must match, and the box's `git worktree list` must show the same branches, detached HEADs and `locked` marks at the box paths, without the worktrees left behind. Anything else: stop and look before going on.
|
|
115
115
|
|
|
116
116
|
## 4. Conversation history (unless the user opted out)
|
|
117
117
|
|
|
@@ -165,36 +165,13 @@ instabox exec "$BOX" --cwd "$DEST" -- 'git status --porcelain | sort; git rev-pa
|
|
|
165
165
|
|
|
166
166
|
Compare with step 3. New `??` lines from the installs (for example a lockfile the project does not commit) are worth a mention; a modified tracked file is not expected: find which step did it.
|
|
167
167
|
|
|
168
|
-
## 7.
|
|
169
|
-
|
|
170
|
-
The plan's `envLeftOut` lists excluded files by name (`jq -r '.main.envLeftOut, (.worktrees[] | select(.move) | .envLeftOut) | .[]' "$W/plan.json"`). Do not print their contents. The new Secret model stores individual key=value entries, not files, and does not create or link a `.env` in the repo.
|
|
171
|
-
|
|
172
|
-
For a project that needs the real values, explain that env delivery makes them readable by code in the box. Use the user's authorization to import the intended file and select its names for this box. Import is org-wide and replaces existing entries with the same names: resolve conflicts and confirm any intended replacement before importing. Different projects needing different values under the same variable name should use separate orgs, or configure their applications to use distinct names; do not silently rename or overwrite a shared credential.
|
|
173
|
-
|
|
174
|
-
After that choice, per approved file (the CLI reads values; saved JSON contains metadata only):
|
|
175
|
-
|
|
176
|
-
```bash
|
|
177
|
-
BOX_ORG=$(instabox get "$BOX" --json | jq -r '.orgId')
|
|
178
|
-
instabox secrets show "$BOX" --json > "$W/selected-secrets.json"
|
|
179
|
-
instabox secrets import "<local .env path>" --org "$BOX_ORG" --delivery env --json > "$W/imported-secrets.json"
|
|
180
|
-
ENV_NAMES=$(jq -c -s '.[0].envSecrets + [.[1].items[].name] | unique' "$W/selected-secrets.json" "$W/imported-secrets.json")
|
|
181
|
-
instabox secrets select "$BOX" --env-secrets "$ENV_NAMES"
|
|
182
|
-
instabox secrets push "$BOX"
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
This merges the approved env names with the box's current env selection and leaves its proxy selection unchanged. Import alone grants no env access to any box. Start a new login shell, or restart/reconfigure the application, to load the updated environment. Use silent presence checks; do not print values to verify delivery.
|
|
186
|
-
|
|
187
|
-
For credentials sent literally in HTTPS headers, save them with `--delivery proxy --host <approved-host>` instead, and select the corresponding proxy names. Every entry in one import shares its delivery mode and host scope, so do not import a mixed `.env` as proxy credentials without separating those decisions. A native database client or a client that computes signatures needs an explicitly selected env value.
|
|
188
|
-
|
|
189
|
-
If the application requires a physical `.env` or another credential file, it needs a separate, explicitly authorized file-transfer or guest-generation workflow with restricted file permissions. Such a file is readable in the guest and may be included in snapshots; it has no Secret-managed file cleanup. Report this requirement rather than claiming Secret import recreates the original file. Tokens and local editor or git configuration are separate setup decisions; metadata labels do not grant credentials.
|
|
190
|
-
|
|
191
|
-
## 8. Tell the user
|
|
168
|
+
## 7. Tell the user
|
|
192
169
|
|
|
193
170
|
- The box name and where the repo is: `instabox ssh <box>`, then `cd /data/workspace/<name>`; each worktree with its box path and branch; worktrees left behind and why.
|
|
194
171
|
- Uncommitted work inside a submodule (a ` M <submodule>` line in step 3) did not come over: name each such submodule so the user can commit or copy that work themselves.
|
|
195
172
|
- Sizes: on disk before, sent after, and the biggest things left out (they were rebuilt or reinstalled on the box).
|
|
196
173
|
- What was installed, whether build and tests pass, and anything left to do (each FAILED step and note from `deps.sh` that is not fixed).
|
|
197
|
-
- Again: git push/pull needs credentials set up on the box.
|
|
174
|
+
- Again: git push/pull needs credentials set up on the box. Ignored files and build output were not copied. Untracked `.env` files were left behind: list them by name from the plan (`jq -r '.main.envLeftOut, (.worktrees[] | select(.move) | .envLeftOut) | .[]' "$W/plan.json"`), never their contents. For an HTTP API key the project needs, the user can run `instabox secrets set NAME --host <api-host>` and select it on the box with `instabox secrets select`; database URLs and other credentials need their own setup on the box. Secrets in committed or staged files, anywhere in `.git` (such as a token in a remote URL in `.git/config`), in untracked files not named `.env*`, or in the copied history, did go over.
|
|
198
175
|
- How to pick up old conversations, kept short, with the session ids from step 4:
|
|
199
176
|
- Claude Code, in the repo (or worktree) directory on the box: `claude --continue` (latest) or `claude --resume` (picker, or `claude --resume <id>`).
|
|
200
177
|
- Codex, in that directory: `codex resume` (picker for this directory), `codex resume --last`, or `codex resume <id>`.
|
|
@@ -325,7 +325,7 @@ project() { # dir label
|
|
|
325
325
|
note "$L: has a compose file; its services were not started (docker compose up -d)"
|
|
326
326
|
for f in .env.example .env.sample .env.template; do
|
|
327
327
|
if [ -f "$f" ] && [ ! -e .env ]; then
|
|
328
|
-
note "$L: expects a .env (see $f); .env files are not copied:
|
|
328
|
+
note "$L: expects a .env (see $f); .env files are not copied: the user sets it up (instabox-move-repo skill, step 7)"
|
|
329
329
|
break
|
|
330
330
|
fi
|
|
331
331
|
done
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// relative to PATH
|
|
11
11
|
// --skip-worktree PATH leave a linked worktree behind (repeatable; pass it to --list0 runs too)
|
|
12
12
|
// --keep NAME copy an excluded name anyway (repeatable): --keep build (not an untracked
|
|
13
|
-
// .env: those
|
|
13
|
+
// .env: those always stay behind)
|
|
14
14
|
//
|
|
15
15
|
// What goes: all of the main checkout's .git (branches, stashes, the index, unpushed commits, the
|
|
16
16
|
// worktrees' own HEAD and index under .git/worktrees/), every tracked file that exists, and every
|
|
@@ -108,7 +108,7 @@ export const EXCLUDED_FILES = [
|
|
|
108
108
|
'.DS_Store',
|
|
109
109
|
];
|
|
110
110
|
|
|
111
|
-
// Untracked .env files never go
|
|
111
|
+
// Untracked .env files never go: the final report lists them as left behind. Templates do.
|
|
112
112
|
const ENV_FILE = /^\.env(?:\..+)?$/;
|
|
113
113
|
const ENV_TEMPLATE = /^\.env\.(?:example|sample|template|dist|defaults)$/;
|
|
114
114
|
const isEnvName = (f) => {
|
|
@@ -18,7 +18,7 @@ instabox snapshot save work --name work-ready --description "deps installed, rep
|
|
|
18
18
|
- A running box is saved live, without stopping it: the snapshot is `pending` in `instabox snapshot ls` until its disks finish uploading (`--no-wait` returns at once).
|
|
19
19
|
- Do not stop the box first: `stop` ends every process in it. A live snapshot is like a clean power cut: what is on disk is kept, what programs hold only in memory is not. Only if the server answers that this box must be stopped, or if a program must write its data to disk first (a database mid-write), run `instabox stop work`, save, then `instabox start work`.
|
|
20
20
|
- `--root-only` saves just the root disk (smaller; `/data` is not included).
|
|
21
|
-
- A disk snapshot includes credential files written by applications, tool sign-ins, and historical Vault files.
|
|
21
|
+
- A disk snapshot includes credential files written by applications, tool sign-ins, and historical Vault files; a suspend snapshot can also retain credentials in process memory. Org Secrets reach the box only as placeholders, so a snapshot holds none of their values, but anything an app or a person wrote to disk is kept. Do not describe snapshots as credential-free. Review copied credentials and rotate upstream when required before sharing or retaining them.
|
|
22
22
|
- Pick names that say what is inside (`node20-playwright`, `api-db-seeded`); names must be unique among your snapshots.
|
|
23
23
|
|
|
24
24
|
## Load
|
|
@@ -50,13 +50,13 @@ instabox create --name work2 --snapshot work-copy
|
|
|
50
50
|
instabox snapshot rm work-copy # optional; work2 is not affected
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
The copy gets a new sandbox identity and the
|
|
53
|
+
The copy gets a new sandbox identity and the Secret selection in its creation request. Without `--secrets` it keeps the existing Vault behavior and does not enroll in org Secrets; it does not inherit the source's selection. To give it neither store's credentials, use:
|
|
54
54
|
|
|
55
55
|
```sh
|
|
56
|
-
instabox create --name work2 --snapshot work-copy --no-vault --secrets none
|
|
56
|
+
instabox create --name work2 --snapshot work-copy --no-vault --secrets none
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
To
|
|
59
|
+
To give the copy API credentials, name them with `--secrets NAME,NAME`. Placeholders copied from the source box do not work for the new one. New selections do not erase credentials that apps or people already wrote into files on the copied disks; review those before sharing the snapshot or the box.
|
|
60
60
|
|
|
61
61
|
## Clean up
|
|
62
62
|
|