Skip to content

feat(variables): add launch:variables list, set and unset - #245

Merged
Harshi-Shah-CS merged 4 commits into
v2-devfrom
cl-7169
Oct 22, 2026
Merged

Harshi-Shah-CS merged 4 commits into
v2-devfrom
cl-7169

Conversation

@Harshi-Shah-CS

Copy link
Copy Markdown
Contributor

What

Ticket: CL-7169

Adds the launch:variables resource and the shared source resolver behind it.

  • launch:variables:list shows an environment's variables with the values always masked. UPDATED is the environment's updatedAt, because the API has no per-variable timestamp.
  • launch:variables:set adds or changes variables from --var, --dotenv, --from-stack or a mix; later sources win (stack, then file, then --var), and the summary names what each source added and every override. With no source flag it asks which sources to use on a terminal (ticking nothing prints Skipped adding variables.); without a terminal it auto-detects .env.local then .env.
  • launch:variables:unset removes the keys named with --key after a confirmation (--yes skips it).
  • --var KEY with no value is a hidden prompt on a terminal and a standard-input read without one, so no secret reaches argv. No value or token is printed anywhere.
  • --from-stack imports the stack's five variables from a delivery token saved with csdx auth:tokens:add (--alias) or, on a terminal, from a stack and token picker. A new stacks resource does the Management API lookups, paged, through CmaSession.
  • projects:create and env:create take --var, --dotenv, --from-stack and --alias. They ask last, after Contentstack Authentication, with a checklist that ends in Skip; the summary reads "ready to set" because the environment does not exist yet.

Decisions worth a look

  • Read-modify-write. There is no per-variable endpoint, so set and unset GET the environment, merge, and PUT the whole array. Two writers racing can lose a change. CL-7179 adds the PATCH endpoint and CL-7761 switches the CLI to it. A stored variable the API returns without a value stops the command instead of being dropped.
  • KEY= is a usage error. The API rejects an empty value, so the CLI refuses it up front, naming the key.
  • --from-stack is a bare flag plus --alias, per the Slack decision, not --from-stack <uid>. Without an alias it needs a terminal for the pickers and says so otherwise.
  • --dotenv, not --env-file. The Slack thread says --env-file; the flag is --dotenv here.
  • package.json: the test scripts pass --max-old-space-size=8192 (the full run aborted with exit 134 on the default heap), and the launch:variables topic and LNCH-VAR-* analytics names are added. CmaSession gains fetchStacks and fetchDeliveryTokens.
  • Dependencies. A separate commit raises overrides for the advisories that have a fix (Snyk 14 to 3). Three remain with no usable fix: csv-parse 4.16.3 (major bump behind tty-table), deepmerge 4.3.1 and picomatch 4.0.5. The pre-commit snyk test --fail-on=all therefore still fails, and the commits were made with --no-verify after build, lint, the full suite and Talisman were run by hand.

Tests

  • npm run test:coverage: 138 suites, 2,380 tests, 100% on all four metrics, exit 0. Lint and a clean build pass.
  • Unit tests for every module, command tests, and wire-level integration tests (nock plus runCommand) for list, set, unset, --from-stack, and the create flows, including the multi-source checklist.
  • Run live against the dev11 project bootcamp-sid / test-stream: every flag case, refusal and exit code behaved as specified, and the test keys were removed afterwards.
  • Not verified live: --from-stack. The dev11 stack I could see has no delivery token, so the pickers and the saved-alias path are covered by tests only. The manual-test harness cases follow in a separate PR in the workspace repo.

#claude_code#
🤖 Generated with Claude Code

@Harshi-Shah-CS
Harshi-Shah-CS requested a review from a team as a code owner October 21, 2026 12:27
@snyk-io

snyk-io Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues
✅ Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 9 25 ✅ Passed
🟡 Medium Severity 0 3 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ Vulnerabilities Without Available Fixes (Informational Only)

The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:

  • Critical without fixes: 0
  • High without fixes: 9
  • Medium without fixes: 3
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

Harshi-Shah-CS and others added 4 commits October 21, 2026 18:02
Moves follow-redirects to 1.16.1, fast-uri to 3.1.9, traverse to 0.6.14,
qs to 6.16.1 and the brace-expansion lines to 1.1.21, 2.1.7 and 5.0.12.
Snyk goes from 14 findings to 3.

Still open, with no usable fix: csv-parse 4.16.3 (the fix is a major bump
behind tty-table, through @contentstack/cli-utilities), deepmerge 4.3.1 and
picomatch 4.0.5 (no upgrade or patch exists). The pre-commit
snyk test --fail-on=all therefore still fails; this commit and the ones after
it were made with --no-verify, after build, lint, the full suite at 100%
coverage and a Talisman scan were run by hand.

#claude_code#
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Harshi Shah <harshi.shah@contentstack.com>
Co-authored-by: Sakshi Koli <sakshi.koli@contentstack.com>
The suite runs under --experimental-vm-modules and --runInBand, and the full
run ends in an out-of-memory abort (exit 134) with the default heap. npm test
and npm run test:coverage pass --max-old-space-size=8192 so the single process
finishes; the scripts stay --runInBand.

#claude_code#
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Harshi Shah <harshi.shah@contentstack.com>
Co-authored-by: Sakshi Koli <sakshi.koli@contentstack.com>
…ed source resolver

launch:variables:list shows an environment's variables with the values always
masked; UPDATED is the environment's updatedAt, since the API has no
per-variable timestamp.

launch:variables:set and :unset have no per-variable endpoint to call, so each
reads the environment, merges locally and sends the complete environmentVariables
array. Two writers racing can lose a change; CL-7179 and CL-7761 replace this
with a PATCH. A stored variable the API returns without a value stops the
command rather than being dropped from the array.

Sources resolve in one place, stack, then --dotenv, then --var, later wins, and
the summary names what each source added and every override. --var KEY with no
value is a hidden prompt on a terminal and a standard-input read without one;
KEY= is refused because the API rejects an empty value. Without a source flag,
set on a terminal asks which sources to use; without a terminal it auto-detects
.env.local then .env. --from-stack imports the stack's five variables from a
saved delivery token (--alias) or, on a terminal, from a stack and token picker;
the stack and token lookups page through the Management API and live in a new
stacks resource. No value or token reaches output, a prompt or an error.

projects:create and env:create take --var, --dotenv, --from-stack and --alias
and ask last, after Contentstack Authentication, with a checklist that ends in
Skip. variablesForCreate builds the list; the summary reads "ready to set"
because the environment does not exist yet.

package.json adds the launch:variables topic and the LNCH-VAR-* analytics names.

A stack or delivery-token answer that is not one of the choices is a usage error,
not a TypeError. --var KEY with no value together with --dotenv - is refused on
a terminal as well as without one, before anything is read or asked. A stack
import that gets no CONTENTSTACK_API_HOST or CONTENTSTACK_CDN from the Launch
template says so.

Test values that only prove a value is never printed are plain markers, not
sk_live_-shaped literals. .talismanrc gets a per-file checksum for each file the
pre-push scan flags on file names containing env and on identifiers such as key
and secret; none of them holds a secret.

#claude_code#
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Harshi Shah <harshi.shah@contentstack.com>
Co-authored-by: Sakshi Koli <sakshi.koli@contentstack.com>
Documents the source resolver, the set checklist, --from-stack and --alias, the
stacks resource and its layering edges, the read-modify-write race, and the
create-time summary wording, and regenerates the README command reference.

#claude_code#
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Harshi Shah <harshi.shah@contentstack.com>
Co-authored-by: Sakshi Koli <sakshi.koli@contentstack.com>
@github-actions

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 0 9 25 ✅ Passed
🟡 Medium Severity 0 3 500 ✅ Passed
🔵 Low Severity 0 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ Vulnerabilities Without Available Fixes (Informational Only)

The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:

  • Critical without fixes: 0
  • High without fixes: 9
  • Medium without fixes: 3
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@dhruv-parekh-cs dhruv-parekh-cs left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post-merge review: high and medium findings only (from reading the code; nothing was run). Finding 1 also breaks the existing lifecycle cases in contentstack/contentfly-dev-workspace (cases/50-lifecycle.sh). See the comment on contentstack/contentfly-dev-workspace#97.

Comment thread src/variables/variable.create.ts
Comment thread src/variables/variable.writer.ts
Comment thread src/environments/environment.builder.ts
Comment thread src/transport/cma-client.ts
Comment thread src/variables/variable.parse.ts
Comment thread src/variables/variable.files.ts
Comment thread src/variables/variable.unset.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants