Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/scripts/evaluate_quality_gate.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const detected = JSON.parse(process.env.DETECTED ?? '{}');
const needs = JSON.parse(process.env.NEEDS ?? '{}');

const required = new Set(['secret-scan']);
const required = new Set();
for (const [job, applicable] of Object.entries(detected)) {
if (applicable === true) required.add(job);
}
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/quality-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ jobs:
heavy: ${{ steps.scope.outputs.heavy }}
secret_scan: ${{ steps.scope.outputs.secret_scan }}
required_contexts: ${{ steps.native.outputs.required_contexts }}
native_required: ${{ steps.native.outputs.required_contexts != '[]' }}
source_sha: ${{ steps.resolve-source.outputs.source_sha }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
Expand Down Expand Up @@ -106,7 +107,7 @@ jobs:
node-ci:
name: node-ci
needs: detect
if: ${{ needs.detect.outputs.node == 'true' && needs.detect.outputs.heavy == 'true' }}
if: ${{ needs.detect.outputs.node == 'true' && needs.detect.outputs.heavy == 'true' && needs.detect.outputs.native_required != 'true' }}
uses: ./.github/workflows/node-pnpm-ci.yml
with:
runs-on: ${{ inputs.linux-runs-on }}
Expand All @@ -116,15 +117,15 @@ jobs:
bun-ci:
name: bun-ci
needs: detect
if: ${{ needs.detect.outputs.bun == 'true' && needs.detect.outputs.heavy == 'true' }}
if: ${{ needs.detect.outputs.bun == 'true' && needs.detect.outputs.heavy == 'true' && needs.detect.outputs.native_required != 'true' }}
uses: ./.github/workflows/bun-ci.yml
with:
runs-on: ${{ inputs.linux-runs-on }}

python-ci:
name: python-ci
needs: detect
if: ${{ needs.detect.outputs.python == 'true' && needs.detect.outputs.heavy == 'true' }}
if: ${{ needs.detect.outputs.python == 'true' && needs.detect.outputs.heavy == 'true' && needs.detect.outputs.native_required != 'true' }}
uses: ./.github/workflows/python-ci.yml
with:
runs-on: ${{ inputs.linux-runs-on }}
Expand All @@ -134,7 +135,7 @@ jobs:
rust-ci:
name: rust-ci
needs: detect
if: ${{ needs.detect.outputs.rust == 'true' && needs.detect.outputs.heavy == 'true' }}
if: ${{ needs.detect.outputs.rust == 'true' && needs.detect.outputs.heavy == 'true' && needs.detect.outputs.native_required != 'true' }}
uses: ./.github/workflows/rust-cargo-ci.yml
with:
runs-on: ${{ inputs.linux-runs-on }}
Expand All @@ -146,14 +147,16 @@ jobs:
# macOS, the org has no self-hosted macOS runner, and GitHub-hosted runners
# are blocked for private repos (zero spending limit) — the job would fail
# at assignment before running a single step. Public repos keep the gate.
if: ${{ needs.detect.outputs.swift == 'true' && needs.detect.outputs.heavy == 'true' && !github.event.repository.private }}
if: ${{ needs.detect.outputs.swift == 'true' && needs.detect.outputs.heavy == 'true' && needs.detect.outputs.native_required != 'true' && !github.event.repository.private }}
uses: ./.github/workflows/swift-ci.yml
with:
runs-on: ${{ inputs.swift-runs-on }}
working-directory: ${{ needs.detect.outputs.swift_directory }}

secret-scan:
name: secret-scan
needs: detect
if: ${{ needs.detect.outputs.native_required != 'true' }}
uses: ./.github/workflows/secret-scan.yml
with:
runs-on: ${{ inputs.linux-runs-on }}
Expand Down Expand Up @@ -278,7 +281,8 @@ jobs:
"bun-ci": ${{ needs.detect.outputs.bun == 'true' && needs.detect.outputs.heavy == 'true' }},
"python-ci": ${{ needs.detect.outputs.python == 'true' && needs.detect.outputs.heavy == 'true' }},
"rust-ci": ${{ needs.detect.outputs.rust == 'true' && needs.detect.outputs.heavy == 'true' }},
"swift-ci": ${{ needs.detect.outputs.swift == 'true' && needs.detect.outputs.heavy == 'true' && !github.event.repository.private }},
"swift-ci": ${{ needs.detect.outputs.swift == 'true' && needs.detect.outputs.heavy == 'true' && needs.detect.outputs.native_required != 'true' && !github.event.repository.private }},
"secret-scan": ${{ needs.detect.outputs.native_required != 'true' }},
"feature-flag-check": ${{ needs.detect.outputs.heavy == 'true' }},
"repository-gates": ${{ needs.detect.outputs.required_contexts != '[]' }}}
run: node .quality-gate-source/.github/scripts/evaluate_quality_gate.mjs
14 changes: 12 additions & 2 deletions tests/test_common_required_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ def test_non_applicable_job_may_be_skipped(self) -> None:
)
self.assertEqual(result.returncode, 0, result.stderr)

def test_secret_scan_is_required_even_when_all_capabilities_are_absent(self) -> None:
def test_secret_scan_is_required_when_selected(self) -> None:
result = self.evaluate(
{"deno-ci": False},
{"deno-ci": False, "secret-scan": True},
{
"deno-ci": {"result": "skipped"},
"secret-scan": {"result": "skipped"},
Expand All @@ -212,6 +212,16 @@ def test_secret_scan_is_required_even_when_all_capabilities_are_absent(self) ->
self.assertNotEqual(result.returncode, 0)
self.assertIn("secret-scan", result.stderr)

def test_secret_scan_may_be_skipped_when_native_gate_owns_it(self) -> None:
result = self.evaluate(
{"deno-ci": False, "secret-scan": False},
{
"deno-ci": {"result": "skipped"},
"secret-scan": {"result": "skipped"},
},
)
self.assertEqual(result.returncode, 0, result.stderr)


if __name__ == "__main__":
unittest.main()
10 changes: 10 additions & 0 deletions tests/test_workflow_wiring.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ def test_native_gate_payload_excludes_unneeded_check_run_fields(self) -> None:
self.assertIn("name: checkRun.name", source)
self.assertIn("workflow_path: match ? runIds.get(match[1]) ?? null : null", source)

def test_native_gate_repositories_do_not_run_duplicate_language_or_secret_gates(self) -> None:
source = QUALITY_GATE.read_text()
self.assertIn("native_required: ${{ steps.native.outputs.required_contexts != '[]' }}", source)
self.assertGreaterEqual(source.count("needs.detect.outputs.native_required != 'true'"), 6)

def test_secret_scan_is_required_only_when_selected(self) -> None:
evaluator = (ROOT / ".github/scripts/evaluate_quality_gate.mjs").read_text()
self.assertIn("const required = new Set();", evaluator)
self.assertNotIn("new Set(['secret-scan'])", evaluator)


if __name__ == "__main__":
unittest.main()