Skip to content
Open
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
9 changes: 6 additions & 3 deletions .github/workflows/ci_cross_repo_integration.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Cross-repo integration test workflow.
# Builds complyctl from the PR branch, checks out complytime-providers@main,
# builds the Ampel provider binary, installs snappy and ampel, and runs the
# cross-repo integration test script to validate the full complyctl + Ampel
# provider pipeline end-to-end.
# builds provider binaries (ampel + opa), installs snappy, ampel, and conftest,
# and runs the cross-repo integration test script to validate the full
# complyctl + provider pipeline end-to-end.
name: Cross-Repo Integration Test

on:
Expand Down Expand Up @@ -58,6 +58,9 @@ jobs:
- name: Install ampel
uses: carabiner-dev/actions/install/ampel@94f29392187fe5082d1195a7d4cae3a7ddf09d9c # v1.2.1

- name: Install conftest
run: go install github.com/open-policy-agent/conftest@v0.68.2

- name: Run cross-repo integration test
env:
PROVIDERS_BIN_DIR: ${{ github.workspace }}/_providers/bin
Expand Down
85 changes: 85 additions & 0 deletions .trivyignore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# SPDX-License-Identifier: Apache-2.0
#
# Trivy misconfig suppressions for K8s Deployment test fixtures.
# These files are intentionally non-compliant or minimally compliant
# to validate OPA provider policy evaluation. They are not deployed
# infrastructure.

misconfigurations:
- id: KSV-0118
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0014
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0001
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0012
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0104
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0003
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0004
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0011
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0015
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0016
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0018
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0020
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0021
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0030
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0106
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
- id: KSV-0110
paths:
- "tests/cross-repo/testdata/test-deployment-bad.yaml"
- "tests/cross-repo/testdata/test-deployment-good.yaml"
statement: Intentional test fixture for OPA provider validation
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ scripts/ # maintenance scripts (SPDX checks, workflow setup)
specs/ # Speckit strategic specifications (NNN-*/ format)
tests/
├── behavioral/ # behavioral test scenarios
├── cross-repo/ # cross-repo integration tests (complyctl + ampel provider)
├── cross-repo/ # cross-repo integration tests (complyctl + ampel + opa providers)
├── e2e/ # E2E tests (build-tag gated: -tags=e2e)
└── integration_test.sh # shell-based integration test
vendor/ # vendored dependencies
Expand Down
4 changes: 2 additions & 2 deletions docs/TESTING_ENVIRONMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,11 @@ complyctl get
# Expected: "Synchronization completed."

# Generate for the OPA provider
complyctl generate --policy-id test-opa-bp
complyctl generate --policy-id test-opa-k8s
# Expected: "Generation completed."

# Run a scan against the test deployment
complyctl scan --policy-id test-opa-bp
complyctl scan --policy-id test-opa-k8s
# Expected: Scan results for container security requirements
```

Expand Down
127 changes: 121 additions & 6 deletions tests/cross-repo/cross_repo_integration_test.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
#
# Cross-repo integration test: complyctl + complytime-provider-ampel.
# Validates the full get → generate → scan pipeline using real binaries
# and the real GitHub API via snappy and ampel.
# Cross-repo integration test: complyctl + complytime-providers (ampel + opa).
# Validates the full get → generate → scan pipeline using real binaries.
# Ampel tests use the real GitHub API via snappy and ampel.
# OPA tests use a local K8s Deployment fixture evaluated by conftest.
#
# Required environment variables:
# PROVIDERS_BIN_DIR Directory containing complyctl-provider-ampel
# PROVIDERS_BIN_DIR Directory containing complyctl-provider-ampel and complyctl-provider-opa
# GITHUB_TOKEN GitHub token with read access to public repositories
#
# Run locally: make test-cross-repo PROVIDERS_BIN_DIR=/path/to/providers/bin
Expand All @@ -22,6 +23,7 @@ TESTDATA_DIR="${REPO_ROOT}/tests/cross-repo/testdata"
REGISTRY_PORT="${GEMARA_SERVICE_PORT:-8765}"
REGISTRY_URL="http://localhost:${REGISTRY_PORT}"
POLICY_ID="test-ampel-bp"
OPA_POLICY_ID="test-opa-k8s"

WORK_DIR=""
TEST_HOME=""
Expand Down Expand Up @@ -133,6 +135,18 @@ if [[ ! -x "${PROVIDER_BINARY}" ]]; then
exit 1
fi

OPA_PROVIDER_BINARY="${PROVIDERS_BIN_DIR}/complyctl-provider-opa"
if [[ ! -x "${OPA_PROVIDER_BINARY}" ]]; then
echo "FATAL: complyctl-provider-opa not found or not executable at ${OPA_PROVIDER_BINARY}"
echo " Build complytime-providers first and set PROVIDERS_BIN_DIR to its bin/ directory."
exit 1
fi

if ! command -v conftest >/dev/null 2>&1; then
echo "FATAL: 'conftest' is required but not installed. The OPA provider requires conftest."
exit 1
fi

if [[ ! -x "${BINARY}" ]]; then
echo "FATAL: complyctl binary not found at ${BINARY}. Run 'make build' first."
exit 1
Expand Down Expand Up @@ -161,9 +175,10 @@ TEST_HOME="$(mktemp -d)"
WORK_DIR="$(mktemp -d)"
export HOME="${TEST_HOME}"

# Install provider binary into the isolated home
# Install provider binaries into the isolated home
mkdir -p "${TEST_HOME}/.complytime/providers"
cp "${PROVIDER_BINARY}" "${TEST_HOME}/.complytime/providers/"
cp "${OPA_PROVIDER_BINARY}" "${TEST_HOME}/.complytime/providers/"
echo " HOME=${TEST_HOME}"
echo " WORK=${WORK_DIR}"

Expand All @@ -176,7 +191,11 @@ sed "s|http://localhost:8765|${REGISTRY_URL}|" \
mkdir -p "${WORK_DIR}/.complytime/ampel/granular-policies"
cp "${TESTDATA_DIR}/granular-policies/block-force-push.json" \
"${WORK_DIR}/.complytime/ampel/granular-policies/"
echo " Workspace config and granular policy copied."

# Copy OPA test fixture into the workspace.
# Start with the non-compliant (bad) fixture; the compliant test swaps it.
cp "${TESTDATA_DIR}/test-deployment-bad.yaml" "${WORK_DIR}/test-deployment.yaml"
echo " Workspace config, granular policy, and OPA test fixture copied."

# Start mock registry.
# 30 retries (15s) — longer than integration_test.sh (15 retries / 7.5s) because
Expand Down Expand Up @@ -293,12 +312,108 @@ test_generate_bad_policy() {
assert_contains "generate bad policy: error message" "${out}" "not found"
}

# --- test_get_opa ---

test_get_opa() {
FOUND_FILE=""
echo ""
echo "=== test_get_opa ==="
# test_get already ran complyctl get which pulls all policies and complypacks.
# Verify OPA-specific artifacts were fetched.
assert_file_exists "get opa: oci-layout exists" \
"${TEST_HOME}/.complytime/policies/policies/test-opa-policy/oci-layout"

# Complypack cache uses evaluator-id/version/ structure.
# Find any content.tar.gz under the opa evaluator directory.
local complypack_match
complypack_match=$(find "${TEST_HOME}/.complytime/complypacks/opa/" \
-name "content.tar.gz" -print -quit 2>/dev/null) || true
if [[ -n "${complypack_match}" && -s "${complypack_match}" ]]; then
pass "get opa: complypack cached"
else
fail "get opa: complypack cached: no content.tar.gz under complypacks/opa/"
fi
}

# --- test_generate_opa ---

test_generate_opa() {
FOUND_FILE=""
echo ""
echo "=== test_generate_opa ==="
local out rc=0
out="$(run_complyctl generate --policy-id "${OPA_POLICY_ID}")" || rc=$?
if [[ "${rc}" -ne 0 ]]; then
fail "generate opa: unexpected exit code ${rc}"
echo "${out}" | sanitize_output >&2
return
fi
echo "${out}" | sanitize_output
assert_contains "generate opa: completed" "${out}" "Generation completed."
}

# --- test_scan_opa (non-compliant fixture — expects failures) ---

test_scan_opa() {
FOUND_FILE=""
echo ""
echo "=== test_scan_opa ==="
local out rc=0
out="$(run_complyctl scan --policy-id "${OPA_POLICY_ID}")" || rc=$?
if [[ "${rc}" -ne 0 ]]; then
fail "scan opa: unexpected exit code ${rc}"
echo "${out}" | sanitize_output >&2
return
fi
echo "${out}" | sanitize_output
assert_contains "scan opa: completed" "${out}" "requirements:"
assert_contains "scan opa: check-run-as-nonroot requirement" "${out}" "check-run-as-nonroot"
assert_contains "scan opa: check-resource-limits requirement" "${out}" "check-resource-limits"
assert_contains "scan opa: failures detected" "${out}" "failed"
}

# --- test_scan_opa_compliant (compliant fixture — expects all pass) ---

test_scan_opa_compliant() {
FOUND_FILE=""
echo ""
echo "=== test_scan_opa_compliant ==="
# Swap in the compliant (good) deployment fixture.
cp "${TESTDATA_DIR}/test-deployment-good.yaml" "${WORK_DIR}/test-deployment.yaml"

local out rc=0
# Re-generate to pick up fresh state, then scan.
out="$(run_complyctl generate --policy-id "${OPA_POLICY_ID}")" || rc=$?
if [[ "${rc}" -ne 0 ]]; then
fail "scan opa compliant: generate failed with exit code ${rc}"
echo "${out}" | sanitize_output >&2
return
fi
rc=0
out="$(run_complyctl scan --policy-id "${OPA_POLICY_ID}")" || rc=$?
if [[ "${rc}" -ne 0 ]]; then
fail "scan opa compliant: unexpected exit code ${rc}"
echo "${out}" | sanitize_output >&2
return
fi
echo "${out}" | sanitize_output
assert_contains "scan opa compliant: completed" "${out}" "requirements:"
assert_contains "scan opa compliant: all passed" "${out}" "passed"

# Restore the non-compliant (bad) fixture for any subsequent tests.
cp "${TESTDATA_DIR}/test-deployment-bad.yaml" "${WORK_DIR}/test-deployment.yaml"
}

# --- Run all tests ---

test_get
test_generate
test_scan
test_generate_bad_policy
test_get_opa
test_generate_opa
test_scan_opa
test_scan_opa_compliant

# --- Summary ---

Expand Down
4 changes: 2 additions & 2 deletions tests/cross-repo/testdata/complytime.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ policies:
- url: http://localhost:8765/policies/test-branch-protection
id: test-ampel-bp
- url: http://localhost:8765/policies/test-opa-policy
id: test-opa-bp
id: test-opa-k8s

complypacks:
- url: http://localhost:8765/complypacks/ampel-bp@v1.0.0
Expand All @@ -19,6 +19,6 @@ targets:
specs: builtin:github/branch-rules.yaml
- id: test-k8s-deployment
policies:
- test-opa-bp
- test-opa-k8s
variables:
input_path: test-deployment.yaml
18 changes: 18 additions & 0 deletions tests/cross-repo/testdata/test-deployment-bad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
spec:
containers:
- name: web
image: nginx:1.27
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
24 changes: 24 additions & 0 deletions tests/cross-repo/testdata/test-deployment-good.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
spec:
containers:
- name: web
image: nginx:1.27
securityContext:
runAsNonRoot: true
resources:
limits:
cpu: "500m"
memory: "128Mi"
3 changes: 3 additions & 0 deletions trivy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
# Trivy configuration — use path-scoped YAML ignore file
ignorefile: ".trivyignore.yaml"
Loading