diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7cd341f60..9136a6d17f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,83 @@ jobs: env: GOOS: ${{ matrix.goos }} + lint-rego: + name: Lint Rego + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + show-progress: false + + - name: Install OPA + uses: open-policy-agent/setup-opa@v2 + with: + version: latest + + # TODO: add summary to $env:GITHUB_STEP_SUMMARY? + - name: Check Policy + shell: pwsh + run: | + $errs = (opa check --strict --max-errors 0 --format json ./pkg/securitypolicy 2>&1) | + ConvertFrom-Json | + Select-Object -ExpandProperty Errors + foreach ( $err in $errs ) { + $title = (Get-Culture).TextInfo.ToTitleCase($err.code -replace "_", " ") + $file = $err.location.file + $line = $err.location.row + $col = $err.location.col + $msg = $err.message + Write-Output "::error file=${file},line=${line},col=${col},title=${title}::${msg}" + } + + if ( $errs.Count -gt 0 ) { + $LASTEXITCODE = 1 + } + continue-on-error: true # TODO!!!!!!!!! + + - name: Check Policy v1 Compatibility + shell: pwsh + run: | + $errs = (opa check --rego-v1 --max-errors 0 --format json ./pkg/securitypolicy 2>&1) | + ConvertFrom-Json | + Select-Object -ExpandProperty Errors + foreach ( $err in $errs ) { + $title = (Get-Culture).TextInfo.ToTitleCase($err.code -replace "_", " ") + $file = $err.location.file + $line = $err.location.row + $col = $err.location.col + $msg = $err.message + Write-Output "::warning file=${file},line=${line},col=${col},title=${title}::${msg}" + } + + if ( $errs.Count -gt 0 ) { + Write-Output "::error title=Rego v1 Compatibility::Policy files are not v1 compatible" + $LASTEXITCODE = 0 + } + + - name: Install Regal + uses: StyraInc/setup-regal@v1 + with: + version: latest + + - name: Lint Policy + run: regal lint --format=github ./pkg/securitypolicy + + - name: Lint Policy Samples + shell: pwsh + # ignore errors in samples code + run: | + # ignore errors in samples code + try { + regal lint --format=github ./internal/regopolicyinterpreter ./internal/tools/policyenginesimulator/samples + } catch { + Write-Output "::error::Policy samples not properly linted." + } finally { + $LASTEXITCODE = 0 + } + protos: runs-on: "windows-2022" @@ -392,7 +469,7 @@ jobs: test/sample-logging-driver.exe integration-tests: - needs: [lint, protos, verify-vendor, go-gen] + needs: [lint, lint-rego, protos, verify-vendor, go-gen] runs-on: ${{ matrix.os }} strategy: fail-fast: false diff --git a/.regal/config.yaml b/.regal/config.yaml new file mode 100644 index 0000000000..a2d9d14881 --- /dev/null +++ b/.regal/config.yaml @@ -0,0 +1,21 @@ +rules: + style: + file-length: + level: warning + + line-length: + level: ignore + # max-line-length: 120 + + # too late to change the names, probably ... + prefer-snake-case: + level: ignore + avoid-get-and-list-prefix: + level: ignore + +ignore: + files: + # ignore test and vendored files + - "*test.rego" + - "test*" + - "vendor*" \ No newline at end of file diff --git a/pkg/securitypolicy/api.rego b/pkg/securitypolicy/api.rego index 82e79c9040..ac15c71e0d 100644 --- a/pkg/securitypolicy/api.rego +++ b/pkg/securitypolicy/api.rego @@ -3,21 +3,21 @@ package api version := "@@API_VERSION@@" enforcement_points := { - "mount_device": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}}, - "mount_overlay": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}}, - "create_container": {"introducedVersion": "0.1.0", "default_results": {"allowed": false, "env_list": null, "allow_stdio_access": false}}, - "unmount_device": {"introducedVersion": "0.2.0", "default_results": {"allowed": true}}, - "unmount_overlay": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}}, - "exec_in_container": {"introducedVersion": "0.2.0", "default_results": {"allowed": true, "env_list": null}}, - "exec_external": {"introducedVersion": "0.3.0", "default_results": {"allowed": true, "env_list": null, "allow_stdio_access": false}}, - "shutdown_container": {"introducedVersion": "0.4.0", "default_results": {"allowed": true}}, - "signal_container_process": {"introducedVersion": "0.5.0", "default_results": {"allowed": true}}, - "plan9_mount": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}}, - "plan9_unmount": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}}, - "get_properties": {"introducedVersion": "0.7.0", "default_results": {"allowed": true}}, - "dump_stacks": {"introducedVersion": "0.7.0", "default_results": {"allowed": true}}, - "runtime_logging": {"introducedVersion": "0.8.0", "default_results": {"allowed": true}}, - "load_fragment": {"introducedVersion": "0.9.0", "default_results": {"allowed": false, "add_module": false}}, - "scratch_mount": {"introducedVersion": "0.10.0", "default_results": {"allowed": true}}, - "scratch_unmount": {"introducedVersion": "0.10.0", "default_results": {"allowed": true}}, + "mount_device": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}}, + "mount_overlay": {"introducedVersion": "0.1.0", "default_results": {"allowed": false}}, + "create_container": {"introducedVersion": "0.1.0", "default_results": {"allowed": false, "env_list": null, "allow_stdio_access": false}}, + "unmount_device": {"introducedVersion": "0.2.0", "default_results": {"allowed": true}}, + "unmount_overlay": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}}, + "exec_in_container": {"introducedVersion": "0.2.0", "default_results": {"allowed": true, "env_list": null}}, + "exec_external": {"introducedVersion": "0.3.0", "default_results": {"allowed": true, "env_list": null, "allow_stdio_access": false}}, + "shutdown_container": {"introducedVersion": "0.4.0", "default_results": {"allowed": true}}, + "signal_container_process": {"introducedVersion": "0.5.0", "default_results": {"allowed": true}}, + "plan9_mount": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}}, + "plan9_unmount": {"introducedVersion": "0.6.0", "default_results": {"allowed": true}}, + "get_properties": {"introducedVersion": "0.7.0", "default_results": {"allowed": true}}, + "dump_stacks": {"introducedVersion": "0.7.0", "default_results": {"allowed": true}}, + "runtime_logging": {"introducedVersion": "0.8.0", "default_results": {"allowed": true}}, + "load_fragment": {"introducedVersion": "0.9.0", "default_results": {"allowed": false, "add_module": false}}, + "scratch_mount": {"introducedVersion": "0.10.0", "default_results": {"allowed": true}}, + "scratch_unmount": {"introducedVersion": "0.10.0", "default_results": {"allowed": true}}, } diff --git a/pkg/securitypolicy/open_door.rego b/pkg/securitypolicy/open_door.rego index 2bc36123d8..85d1706097 100644 --- a/pkg/securitypolicy/open_door.rego +++ b/pkg/securitypolicy/open_door.rego @@ -3,19 +3,35 @@ package policy api_version := "@@API_VERSION@@" mount_device := {"allowed": true} + mount_overlay := {"allowed": true} + create_container := {"allowed": true, "env_list": null, "allow_stdio_access": true} + unmount_device := {"allowed": true} + unmount_overlay := {"allowed": true} + exec_in_container := {"allowed": true, "env_list": null} + exec_external := {"allowed": true, "env_list": null, "allow_stdio_access": true} + shutdown_container := {"allowed": true} + signal_container_process := {"allowed": true} + plan9_mount := {"allowed": true} + plan9_unmount := {"allowed": true} + get_properties := {"allowed": true} + dump_stacks := {"allowed": true} + runtime_logging := {"allowed": true} + load_fragment := {"allowed": true} + scratch_mount := {"allowed": true} + scratch_unmount := {"allowed": true} diff --git a/pkg/securitypolicy/policy.rego b/pkg/securitypolicy/policy.rego.partial similarity index 100% rename from pkg/securitypolicy/policy.rego rename to pkg/securitypolicy/policy.rego.partial diff --git a/pkg/securitypolicy/securitypolicy_marshal.go b/pkg/securitypolicy/securitypolicy_marshal.go index f9ca3a3013..918c15e20f 100644 --- a/pkg/securitypolicy/securitypolicy_marshal.go +++ b/pkg/securitypolicy/securitypolicy_marshal.go @@ -41,7 +41,7 @@ func init() { registeredMarshallers[regoMarshaller] = marshalRego } -//go:embed policy.rego +//go:embed policy.rego.partial var policyRegoTemplate string //go:embed open_door.rego