Skip to content

PPLT-6233: Export PERCY_CLI_API and CYPRESS_PERCY_SERVER_ADDRESS from percy exec - #2466

Open
RaghavsBrowserStack wants to merge 1 commit into
masterfrom
PPLT-6233-export-cli-address
Open

RaghavsBrowserStack wants to merge 1 commit into
masterfrom
PPLT-6233-export-cli-address

Conversation

@RaghavsBrowserStack

@RaghavsBrowserStack RaghavsBrowserStack commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Jira: https://browserstack.atlassian.net/browse/PPLT-6233 (epic PPLT-6210)

Problem

percy exec --port <N> exports only PERCY_SERVER_ADDRESS to the child command. The Python and .NET SDKs (Selenium and Playwright) read PERCY_CLI_API instead, and the Cypress browser only sees CYPRESS_* variables. With a non-default port these SDKs fall back to localhost:5338, log Percy is not running, disabling snapshots, and the command exits 0 with an empty build.

Pre-existing, not caused by the framework upgrades. Cypress 16 makes it more visible because it removed Cypress.env().

Fix

When Percy is running, percy exec now also exports:

  • PERCY_CLI_API (Python and .NET SDKs)
  • CYPRESS_PERCY_SERVER_ADDRESS (Cypress ≤15 via Cypress.env(); on 16 CYPRESS_* vars still populate cy.env())

Both get the same address as PERCY_SERVER_ADDRESS. A value the user already set is kept. Neither is exported when Percy is disabled, so the SDKs keep their own defaults.

Cypress 16 expose: not exported. The Cypress migration guide, Cypress.expose API and environment variables guide document only two ways to set expose values: the config file and the --expose/-x CLI flag. They say CYPRESS_* OS variables "populate env only" and "never reach Cypress.expose()". There is no CYPRESS_EXPOSE_* or similar env-var route, so on Cypress 16 @percy/cypress must read the address via cy.env() or a task, not Cypress.expose().

Testing

  • New cli-exec unit tests: all three address vars reach the child; values the user set are kept; nothing extra is exported when Percy is disabled. All pass.
  • Locally, yarn test in packages/cli-exec has 2 failures on this branch: handles terminating the child process when interrupted and exec:start starts a long-running percy process. These are timing/signal specs. Master also fails locally (3 failures, including the interrupt spec), so they are not caused by this change. Leaving it to CI.
  • Real build, example-percy-selenium-python, percy exec --port 5501, PERCY_CLI_API not set:

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Child processes now receive the configured Percy server address through supported environment variables, while preserving any alternate values explicitly set by the user.
    • Alternate server address variables are not set when Percy is disabled.

… percy exec

The Python and .NET SDKs read PERCY_CLI_API and the Cypress browser only
sees CYPRESS_-prefixed vars, so with a non-default --port they fell back
to 5338 and silently disabled snapshots. Export both with the server
address, keeping any value the user already set.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Some coding-guideline sources were skipped; the reason is listed next to each one. Other guidelines were applied as usual. On a public repository, sources from your configuration are listed without their names.

Skipped guideline sources: 1
a configured source — couldn't be fetched

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited), Workspace UI (inherited)
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: 23b26bfb-dc0a-470e-af7c-ca2beb0e0211
📥 Commits

Reviewing files that changed from the base of the PR and between abb8d63 and 6539aa2.

📒 Files selected for processing: 2
  • packages/cli-exec/src/exec.js
  • packages/cli-exec/test/exec.test.js

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 5 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout: 1
  • GitHub Check: Test @percy/core
⚠️ CI failures not shown inline: 1

Commit Status: percy/Percy-CLI-regression-a6beeeec: percy/Percy-CLI-regression-a6beeeec

Conclusion: failure

1 visual change needs review
🔇 Additional comments: 2
packages/cli-exec/src/exec.js: 1

111-119: LGTM!

packages/cli-exec/test/exec.test.js: 1

29-31: LGTM!

Also applies to: 433-459

📝 Walkthrough

The exec environment now sets PERCY_SERVER_ADDRESS and, when an address is available, sets PERCY_CLI_API and CYPRESS_PERCY_SERVER_ADDRESS only when those variables are unset.

Changes: Server address environment

Layer / File(s) Summary
Propagate server address to child processes
packages/cli-exec/src/exec.js, packages/cli-exec/test/exec.test.js
exec sets the Percy server address variables for child processes. Tests cover address propagation, preservation of existing alternate-variable values, and the Percy-disabled case.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Suggested reviewers: wwilsman

Merge Risk: ⚪ Minimal · up to 6539a

The new variables direct child SDKs to the selected Percy server while preserving explicit values, and the health-check still verifies reachability. The reported test failures remain unverified; confirm the package test workflow in CI. No introduced issue is established.

Pre-merge checks: Passed 4
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title includes the valid Jira ID PPLT-6233 and clearly describes the exported environment variables added by the change.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@RaghavsBrowserStack RaghavsBrowserStack left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude Code Review (automated) — 3 inline finding(s). Full report in the PR comment below. Verdict: Passed.

if (address) {
// the Python and .NET SDKs read PERCY_CLI_API, and Cypress only forwards CYPRESS_-prefixed
// vars to the browser; without these a non-default --port leaves those SDKs on 5338
env.PERCY_CLI_API ||= address;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[Medium] Inherited or stale value silently wins over the live --port address

||= keeps any PERCY_CLI_API or CYPRESS_PERCY_SERVER_ADDRESS already in the environment, for example from an outer percy exec or a CI config hard-coding :5338. PERCY_SERVER_ADDRESS is always overwritten, so with --port 4567 the vars disagree and the Python, .NET and Cypress SDKs silently hit the wrong server. That is the bug this PR fixes.

Suggestion: Overwrite unconditionally like PERCY_SERVER_ADDRESS, or keep ||= and log.debug/log.warn when the kept value differs from address. Either way, document the precedence.

Reviewer: stack:percy-cli-code-review, stack-percy-cli-code-reviewer

// provide SDKs with useful env vars
env.PERCY_SERVER_ADDRESS = percy?.address();
let address = percy?.address();
env.PERCY_SERVER_ADDRESS = address;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[Low] PERCY_SERVER_ADDRESS becomes the string "undefined" when Percy is disabled (pre-existing)

env is process.env (cli-command/src/command.js:219), so assigning undefined stores "undefined". The new if (address) guard protects only the two new vars.

Suggestion: Move this assignment inside the guard. A follow-up PR is fine.

Reviewer: stack:percy-cli-code-review, stack-percy-cli-code-reviewer

].join('')])).toBeResolved();
});

it('does not export the alternate server address env vars when percy is disabled', async () => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[Low] Disabled-path spec doesn't assert that Percy was actually disabled

This spec only checks that the vars are absent. There is also no spec for an inherited or stale value.

Suggestion: Assert [percy] Percy is disabled in logger.stderr, and add a nested or stale spec once the ||= precedence is decided.

Reviewer: stack:percy-cli-code-review, stack-percy-cli-code-reviewer

@RaghavsBrowserStack

Copy link
Copy Markdown
Contributor Author

Claude Code PR Review

PR: #2466 • Head: 6539aa2 • Reviewers: stack:percy-cli-code-review, stack-percy-cli-code-reviewer, stack-percy-docs-reviewer

Summary

percy exec (and app:exec, which shares the callback) now also exports PERCY_CLI_API and CYPRESS_PERCY_SERVER_ADDRESS. Both are set to percy.address() when Percy is running, and a value the user already set is kept (||=). This lets the Python, .NET and Cypress SDKs follow a non-default --port. Three new cli-exec specs cover it.

Review Table

Priority Category Check Status Notes
High Security No hardcoded secrets or credentials Pass Only a localhost address is exported. No token.
High Security Authentication/authorization checks present N/A No auth surface.
High Security Input validation and sanitization N/A The value comes from percy.address(), not from user input.
High Security No IDOR — resource ownership validated N/A
High Security No SQL injection (parameterized queries) N/A
High Correctness Logic is correct, handles edge cases Pass Correct for the target case. Medium edge case: an inherited or stale value wins over --port (see Findings).
High Correctness Error handling is explicit, no swallowed exceptions N/A
High Correctness No race conditions or concurrency issues Pass Synchronous env setup before spawn.
Medium Testing New code has corresponding tests Pass Specs cover the default port, a user override, and Percy disabled. The beforeEach cleanup clears the new vars.
Medium Testing Error paths and edge cases tested Fail (Low) No spec for an inherited or stale value. The disabled spec doesn't assert that Percy was disabled.
Medium Testing Existing tests still pass (no regressions) Pass The PR notes 2 local timing/signal flakes that also fail on master. CI is authoritative.
Medium Performance No N+1 queries or unbounded data fetching N/A
Medium Performance Long-running tasks use background jobs N/A
Medium Quality Follows existing codebase patterns Pass `
Medium Quality Changes are focused (single concern) Pass
Low Quality Meaningful names, no dead code Pass
Low Quality Comments explain why, not what Pass The comment at 115-116 explains why.
Low Quality No unnecessary dependencies added Pass No new dependencies.

Findings

  • File: packages/cli-exec/src/exec.js:117

  • Severity: Medium

  • Reviewer: stack:percy-cli-code-review, stack-percy-cli-code-reviewer

  • Issue: ||= keeps any value of PERCY_CLI_API or CYPRESS_PERCY_SERVER_ADDRESS that is already in the environment, while PERCY_SERVER_ADDRESS is always overwritten. The value might come from an outer percy exec, or be hard-coded in CI (for example PERCY_CLI_API=http://localhost:5338). With --port 4567 the three vars then disagree, and the Python, .NET and Cypress SDKs silently talk to the wrong server. That brings back the bug this PR fixes, with nothing logged.

  • Suggestion: Make the precedence explicit. Either overwrite unconditionally, as PERCY_SERVER_ADDRESS already is (--port is the explicit signal), or keep ||= and log.debug/log.warn when the kept value differs from address. Record the decision in the PR description, and consider a spec for the nested or stale case.

  • File: packages/cli-exec/src/exec.js:112

  • Severity: Low

  • Reviewer: stack:percy-cli-code-review, stack-percy-cli-code-reviewer

  • Issue: This predates the PR, but the block was touched. env is process.env (cli-command/src/command.js:219). When Percy is disabled, env.PERCY_SERVER_ADDRESS = undefined stores the string "undefined". The same happens to PERCY_BUILD_ID and PERCY_BUILD_URL. The new if (address) guard protects only the two new vars.

  • Suggestion: Optionally move the PERCY_SERVER_ADDRESS assignment inside the guard (or delete the var when there is no address). A follow-up PR is fine.

  • File: packages/cli-exec/test/exec.test.js:453

  • Severity: Low

  • Reviewer: stack:percy-cli-code-review, stack-percy-cli-code-reviewer

  • Issue: The disabled-path spec only checks that the two vars are absent. It never asserts that Percy actually ran in the disabled path. There is also no spec for an inherited or stale value.

  • Suggestion: Assert [percy] Percy is disabled in logger.stderr. Add a nested or stale spec once the precedence for the Medium finding above is settled.

  • File: packages/cli-exec/src/exec.js:115

  • Severity: Low

  • Reviewer: stack:percy-cli-code-review

  • Issue: percy exec now exports new env vars that users will see, but there is no changelog note (rules/commit-conventions.md, rule 5).

  • Suggestion: Add a release-notes line to the PR description.

Docs coverage

stack-percy-docs-reviewer: N/A. This isn't an architectural change, so no KB PR was opened. Optional, not gating: when .claude/knowledge/domain/GLOSSARY.md, PRODUCT.md and FEATURE-FLAGS.md are next edited, mention the two new vars in their lists of daemon-address env vars.


Verdict: PASS — the change is correct and tested, with no High or Critical findings. Settle the ||= precedence question before merge.

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.

1 participant