ci: require Azure Trusted Signing vars before a downloadable Windows build
batch-sign-binaries.mjs and electron-builder.config.cjs::windowsSigning treat a missing AZURE_SIGN_* set as "sign nothing, warn" — right for a fork or a local build, but a release-signing lane with the vars unprovisioned would have published UNSIGNED installers with only a console.warn in the log. The macOS leg already refuses to build without CSC/Apple credentials under the publishing gate; the Windows legs now do the same for the Azure vars, before any payload is built.
This commit is contained in:
24
.github/workflows/desktop-bundled-release.yml
vendored
24
.github/workflows/desktop-bundled-release.yml
vendored
@@ -497,6 +497,30 @@ jobs:
|
||||
payload-signatures-v1-${{ runner.os }}-${{ matrix.target.label }}-
|
||||
payload-signatures-v1-${{ runner.os }}-
|
||||
|
||||
# Downloadable artifacts (commit builds, candidates, published tags,
|
||||
# channels) must be Authenticode-signed. Without the Azure Trusted
|
||||
# Signing vars the build only warns and ships UNSIGNED binaries, which
|
||||
# is right for a fork or a local build and wrong for a release.
|
||||
- name: Require Azure signing when publishing
|
||||
if: inputs.upload_release == true || inputs.release-phase == 'candidate' || inputs.build_commit != '' || inputs.channel != ''
|
||||
shell: bash
|
||||
env:
|
||||
AZURE_SIGN_ENDPOINT: ${{ vars.AZURE_SIGN_ENDPOINT }}
|
||||
AZURE_SIGN_ACCOUNT: ${{ vars.AZURE_SIGN_ACCOUNT }}
|
||||
AZURE_SIGN_PROFILE: ${{ vars.AZURE_SIGN_PROFILE }}
|
||||
AZURE_SIGN_PUBLISHER: ${{ vars.AZURE_SIGN_PUBLISHER }}
|
||||
AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
|
||||
AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
|
||||
run: |
|
||||
missing=()
|
||||
for name in AZURE_SIGN_ENDPOINT AZURE_SIGN_ACCOUNT AZURE_SIGN_PROFILE AZURE_SIGN_PUBLISHER AZURE_CLIENT_ID AZURE_TENANT_ID; do
|
||||
[ -z "${!name}" ] && missing+=("$name")
|
||||
done
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
echo "::error::required Azure Trusted Signing vars are missing from release-signing: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Azure login (OIDC)
|
||||
if: vars.AZURE_CLIENT_ID != ''
|
||||
uses: azure/login@f5d393ae46f8fde4be8b75f32e3fc50e654ad0ca # v3.0.1
|
||||
|
||||
@@ -223,3 +223,34 @@ def test_malformed_tag_is_refused_before_any_git_work(tmp_path: Path):
|
||||
"not a release tag" in proc.stdout + proc.stderr
|
||||
or "does not match pyproject.toml version" in proc.stdout + proc.stderr
|
||||
)
|
||||
|
||||
|
||||
def _require_step(job: str, name_prefix: str) -> dict:
|
||||
steps = _workflow()["jobs"][job]["steps"]
|
||||
(step,) = [s for s in steps if isinstance(s, dict) and s.get("name", "").startswith(name_prefix)]
|
||||
return step
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("bash") is None, reason="needs bash")
|
||||
def test_downloadable_windows_builds_refuse_to_ship_unsigned(tmp_path: Path):
|
||||
"""The Windows signer only warns without AZURE_SIGN_*; every lane whose
|
||||
artifacts are downloadable must therefore fail before building, under
|
||||
the same gate the macOS leg uses for its signing credentials."""
|
||||
step = _require_step("build-win32-release", "Require Azure signing")
|
||||
assert step["if"] == _require_step("build-darwin-release", "Require signing credentials")["if"]
|
||||
assert "build-commit" not in step["if"] and "release-phase == 'candidate'" in step["if"]
|
||||
names = list(step["env"])
|
||||
assert {"AZURE_SIGN_ENDPOINT", "AZURE_SIGN_ACCOUNT", "AZURE_SIGN_PROFILE", "AZURE_CLIENT_ID"} <= set(names)
|
||||
|
||||
def run(**values: str) -> subprocess.CompletedProcess:
|
||||
env = {"PATH": os.environ["PATH"], "RUNNER_TEMP": str(tmp_path)}
|
||||
env.update({name: "" for name in names})
|
||||
env.update(values)
|
||||
return subprocess.run(["bash", "-euo", "pipefail", "-c", step["run"]], env=env,
|
||||
capture_output=True, text=True, timeout=60)
|
||||
|
||||
proc = run()
|
||||
assert proc.returncode != 0 and "::error::" in proc.stdout and "AZURE_SIGN_ENDPOINT" in proc.stdout
|
||||
assert run(**{name: "x" for name in names}).returncode == 0
|
||||
partial = run(**{name: "x" for name in names if name != "AZURE_CLIENT_ID"})
|
||||
assert partial.returncode != 0 and "AZURE_CLIENT_ID" in partial.stdout
|
||||
|
||||
Reference in New Issue
Block a user