fix(ci): address reviewer feedback on Dockerfile.server security scan

- Pin Trivy installation to v0.57.1 with checksum verification instead
  of the insecure curl-pipe-sh install pattern
- Fix BDD step context initialization: load workflow_content in the
  Background step so scenarios 17/24/31 no longer error with AttributeError
- Fix ruff format violations in step definitions
- Add Robot Framework integration test verifying CI scan configuration
- Add CHANGELOG entry for issue #1927

ISSUES CLOSED: #1927
This commit is contained in:
2026-06-10 02:56:05 -04:00
committed by Forgejo
parent 4f924d5c59
commit c3c3c224c4
4 changed files with 111 additions and 31 deletions
@@ -16,15 +16,23 @@ def step_dockerfile_server_exists(context):
@given("Trivy is available in the CI environment")
def step_trivy_available(context):
"""Verify that Trivy is available (or will be in CI)."""
# In CI, Trivy will be installed. For local testing, we just note this requirement.
context.trivy_required = True
workflow_path = Path(".forgejo/workflows/ci.yml")
if workflow_path.exists():
with open(workflow_path) as f:
context.workflow_content = f.read()
else:
context.workflow_content = ""
context.workflow_path = workflow_path
@given("the CI workflow file exists at .forgejo/workflows/ci.yml")
def step_ci_workflow_exists(context):
"""Verify that the CI workflow file exists."""
workflow_path = Path(".forgejo/workflows/ci.yml")
assert workflow_path.exists(), "CI workflow file not found at .forgejo/workflows/ci.yml"
assert workflow_path.exists(), (
"CI workflow file not found at .forgejo/workflows/ci.yml"
)
context.workflow_path = workflow_path
@@ -40,31 +48,38 @@ def step_examine_docker_job(context):
def step_docker_job_includes_scan_step(context):
"""Verify that the docker job includes a security scan step."""
# Look for a step that scans the Dockerfile.server image
assert "Dockerfile.server" in context.workflow_content, \
assert "Dockerfile.server" in context.workflow_content, (
"Dockerfile.server not referenced in docker job"
)
# Look for Trivy or security scanning references
assert "trivy" in context.workflow_content.lower() or "scan" in context.workflow_content.lower(), \
"No security scanning step found in docker job"
assert (
"trivy" in context.workflow_content.lower()
or "scan" in context.workflow_content.lower()
), "No security scanning step found in docker job"
@then("the scan step should use Trivy or equivalent tool")
def step_scan_uses_trivy(context):
"""Verify that the scan step uses Trivy."""
assert "trivy" in context.workflow_content.lower(), \
"Trivy not found in CI workflow"
assert "trivy" in context.workflow_content.lower(), "Trivy not found in CI workflow"
@then("the scan step should be configured to fail on HIGH or CRITICAL severity findings")
@then(
"the scan step should be configured to fail on HIGH or CRITICAL severity findings"
)
def step_scan_fails_on_high_severity(context):
"""Verify that the scan is configured to fail on HIGH or CRITICAL findings."""
# Look for severity configuration
assert "HIGH" in context.workflow_content or "CRITICAL" in context.workflow_content, \
"Severity configuration not found in scan step"
assert (
"HIGH" in context.workflow_content or "CRITICAL" in context.workflow_content
), "Severity configuration not found in scan step"
# Look for exit code handling
assert "exit" in context.workflow_content.lower() or "fail" in context.workflow_content.lower(), \
"Exit code handling not configured for scan failures"
assert (
"exit" in context.workflow_content.lower()
or "fail" in context.workflow_content.lower()
), "Exit code handling not configured for scan failures"
@given("a Dockerfile.server image has been built")
@@ -84,23 +99,26 @@ def step_execute_security_scan(context):
def step_scan_results_displayed(context):
"""Verify that scan results are displayed in output."""
# In CI, this is handled by the workflow output
assert "scan" in context.workflow_content.lower(), \
assert "scan" in context.workflow_content.lower(), (
"Scan output not configured in workflow"
)
@then("the output should include a summary of vulnerabilities found")
def step_output_includes_summary(context):
"""Verify that output includes vulnerability summary."""
# Trivy provides summary by default
assert "trivy" in context.workflow_content.lower(), \
assert "trivy" in context.workflow_content.lower(), (
"Trivy not configured to provide output"
)
@then("the output should indicate the severity levels of findings")
def step_output_includes_severity(context):
"""Verify that output includes severity levels."""
assert "HIGH" in context.workflow_content or "CRITICAL" in context.workflow_content, \
"Severity levels not indicated in output configuration"
assert (
"HIGH" in context.workflow_content or "CRITICAL" in context.workflow_content
), "Severity levels not indicated in output configuration"
@given("a Dockerfile.server image with known HIGH severity vulnerabilities")
@@ -113,24 +131,25 @@ def step_image_with_vulnerabilities(context):
def step_scan_exits_nonzero(context):
"""Verify that scan exits with non-zero status on vulnerabilities."""
# This is verified by the workflow configuration
assert "trivy" in context.workflow_content.lower(), \
"Trivy not configured"
assert "trivy" in context.workflow_content.lower(), "Trivy not configured"
@then("the CI job should fail")
def step_ci_job_fails(context):
"""Verify that the CI job fails on vulnerabilities."""
# The workflow should be configured to fail on scan failure
assert "docker" in context.workflow_content.lower(), \
assert "docker" in context.workflow_content.lower(), (
"Docker job not found in workflow"
)
@then("the failure should block merge to master")
def step_failure_blocks_merge(context):
"""Verify that job failure blocks merge."""
# This is enforced by branch protection rules
assert "docker" in context.workflow_content.lower(), \
assert "docker" in context.workflow_content.lower(), (
"Docker job not configured as required check"
)
@given("a Dockerfile.server image with no HIGH or CRITICAL severity vulnerabilities")
@@ -143,21 +162,20 @@ def step_image_without_vulnerabilities(context):
def step_scan_exits_zero(context):
"""Verify that scan exits with zero status on clean image."""
# Trivy exits 0 when no HIGH/CRITICAL vulnerabilities found
assert "trivy" in context.workflow_content.lower(), \
"Trivy not configured"
assert "trivy" in context.workflow_content.lower(), "Trivy not configured"
@then("the CI job should pass")
def step_ci_job_passes(context):
"""Verify that the CI job passes on clean image."""
# The workflow should allow the job to pass
assert "docker" in context.workflow_content.lower(), \
assert "docker" in context.workflow_content.lower(), (
"Docker job not found in workflow"
)
@then("the build can proceed to the next stage")
def step_build_proceeds(context):
"""Verify that the build can proceed after passing scan."""
# The workflow should have subsequent jobs that depend on docker job
assert "needs:" in context.workflow_content, \
"Job dependencies not configured"
assert "needs:" in context.workflow_content, "Job dependencies not configured"