From ca69aa74677d43bd54b08fae12fd0c92c660a36d Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Wed, 13 May 2026 23:14:52 +0100 Subject: [PATCH 01/10] chore: check and report four-eyes to Kosli --- .github/workflows/init_kosli.yml | 35 +++- bin/never_alone/4eyes.sh | 16 ++ bin/never_alone/four-eyes-policy.rego | 209 +++++++++++++++++++ bin/never_alone/four-eyes-result-schema.json | 46 ++++ bin/never_alone/setup_attestation_type.sh | 24 +++ 5 files changed, 323 insertions(+), 7 deletions(-) create mode 100755 bin/never_alone/4eyes.sh create mode 100644 bin/never_alone/four-eyes-policy.rego create mode 100644 bin/never_alone/four-eyes-result-schema.json create mode 100755 bin/never_alone/setup_attestation_type.sh diff --git a/.github/workflows/init_kosli.yml b/.github/workflows/init_kosli.yml index 6ab5f097e..52468b37d 100644 --- a/.github/workflows/init_kosli.yml +++ b/.github/workflows/init_kosli.yml @@ -23,7 +23,7 @@ on: required: false type: string default: 'none' - secrets: + secrets: kosli_api_token: required: true pr_github_token: @@ -75,8 +75,8 @@ jobs: if: ${{ inputs.report_to_kosli != 'none' }} env: KOSLI_API_TOKEN: ${{ secrets.kosli_api_token }} - run: kosli begin trail ${{inputs.trail_name}} - --flow ${{inputs.flow_name}} + run: kosli begin trail ${{inputs.trail_name}} + --flow ${{inputs.flow_name}} --org ${{inputs.kosli_org}} - name: Report pull-request attestation to Kosli @@ -85,11 +85,32 @@ jobs: KOSLI_API_TOKEN: ${{ secrets.kosli_api_token }} run: kosli attest pullrequest github --flow ${{inputs.flow_name}} - --trail ${{inputs.trail_name}} + --trail ${{inputs.trail_name}} --name pr --github-token ${{ secrets.pr_github_token }} --org ${{inputs.kosli_org}} - + + - name: Evaluate trails for four-eyes to Kosli + if: ${{ inputs.report_to_kosli == 'all' }} + env: + KOSLI_API_TOKEN: ${{ secrets.kosli_api_token }} + run: kosli evaluate trails ${{inputs.trail_name}} \ + --policy "./bin/never_alone/four-eyes-policy.rego" \ + --show-input \ + --flow ${{inputs.flow_name}} \ + --output json > "4eyes-eval-${{inputs.trail_name}}.json" 2>/dev/null || true + + - name: Report four-eyes attestation to Kosli + if: ${{ inputs.report_to_kosli == 'all' }} + env: + KOSLI_API_TOKEN: ${{ secrets.kosli_api_token }} + run: kosli attest custom \ + --type "four-eyes-result" \ + --name "four-eyes-result" \ + --attestation-data "4eyes-eval-${{inputs.trail_name}}.json" \ + --attachments "./bin/never_alone/four-eyes-policy.rego" \ + --trail ${{inputs.trail_name}} \ + --flow ${{inputs.flow_name}} - name: Report never-alone attestation to Kosli if: ${{ inputs.report_to_kosli == 'all' }} @@ -99,8 +120,8 @@ jobs: GH_TOKEN: ${{ github.token }} run: | USER_DATA_FILENAME=never-alone-user-data.json - ./bin/never_alone/get_commit_and_pr_info.sh -c ${GITHUB_SHA} -o ${USER_DATA_FILENAME} - + ./bin/never_alone/get_commit_and_pr_info.sh -c ${GITHUB_SHA} -o ${USER_DATA_FILENAME} + PR_URL=$(cat ${USER_DATA_FILENAME} | jq -r '.pullRequest.url // empty') if [ -n "$PR_URL" ]; then PR_ANNOTATE_ARG="--annotate pull_request=$PR_URL" diff --git a/bin/never_alone/4eyes.sh b/bin/never_alone/4eyes.sh new file mode 100755 index 000000000..ad9307049 --- /dev/null +++ b/bin/never_alone/4eyes.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +KOSLI_ORG=kosli-public +KOSLI_FLOW=cli-release + +#kosli list trails --flow $KOSLI_FLOW +kosli evaluate trails "a2ee562" --flow cli --policy four-eyes-policy.rego --params '{"attestation_name": "pr"}' --show-input --output json + +#echo "Attesting release evaluation result to trail ${CURRENT_TAG}..." +#kosli attest custom \ +# --type "four-eyes-result" \ +# --name "four-eyes-result" \ +# --attestation-data "${EVAL_FILE}" \ +# --attachments "${SCRIPT_DIR}/four-eyes-policy.rego" \ +# --trail "${CURRENT_TAG}" \ +# --flow "${KOSLI_FLOW}" diff --git a/bin/never_alone/four-eyes-policy.rego b/bin/never_alone/four-eyes-policy.rego new file mode 100644 index 000000000..b53e114ab --- /dev/null +++ b/bin/never_alone/four-eyes-policy.rego @@ -0,0 +1,209 @@ +package policy + +import rego.v1 + +# Four-eyes principle enforcement: every commit must have independent review. +# This policy evaluates per-commit attestation data from Kosli and passes only +# when all violations are resolved. +default allow = false + +allow if count(violation_reasons) == 0 + +# Set PR attestation name +attestation_name := name if { + name := data.params.attestation_name + is_string(name) +} else := "pr-review" + +# --------------------------------------------------------------------------- +# Attestation data +# +# Used with `kosli evaluate trails` (plural). Each trail in input.trails +# represents one commit. The PR attestation payload is at: +# trail.compliance_status.attestations_statuses["pr-review"] +# +# Attested via: kosli attest pullrequest github --name pr-review --commit +# --------------------------------------------------------------------------- + +# Extract PR attestation payload from a trail. +pr_attest(trail) := trail.compliance_status.attestations_statuses[attestation_name] + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + +# GitHub usernames of all PR branch commit authors whose identity was resolved. +pr_commit_authors(pr) := {u | + some c in pr.commits + u := c.author_username + u != null +} + +# Latest Unix timestamp among PR branch commits. +latest_commit_ts(pr) := max({c.timestamp | some c in pr.commits}) + +# A commit is the merge commit when the PR's merge_commit field matches the +# trail name (which is the commit SHA). Covers squash, regular, and rebase merges. +is_merge_commit(trail, pr) if { + trail.name == pr.merge_commit +} + +# Regular commit: PR branch authors + PR author all need independent approval after last code commit. +has_independent_approval(trail, pr) if { + not is_merge_commit(trail, pr) + cutoff := latest_commit_ts(pr) + all_authors := pr_commit_authors(pr) | {pr.author} + count(all_authors) > 0 + every author in all_authors { + some approver in pr.approvers + approver.state == "APPROVED" + is_string(approver.username) + approver.username != author + approver.timestamp > cutoff + } +} + +# Merge commit: only PR branch commit authors need independent approval. +# The merge button clicker did not write code and requires no separate review. +has_independent_approval(trail, pr) if { + is_merge_commit(trail, pr) + cutoff := latest_commit_ts(pr) + all_authors := pr_commit_authors(pr) + count(all_authors) > 0 + every author in all_authors { + some approver in pr.approvers + approver.state == "APPROVED" + is_string(approver.username) + approver.username != author + approver.timestamp > cutoff + } +} + +# --------------------------------------------------------------------------- +# Service account exemption +# +# Matched against trail.git_commit_info.author, which is "Name " format. +# Patterns work against the full string, e.g.: +# "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" +# --------------------------------------------------------------------------- + +service_account_patterns := { + "svc_.*", + ".*\\[bot\\]", + "noreply@github.com" +} + +# Commit author is a service account (CI, GitHub Actions, dependabot, etc). +is_service_account(trail) if { + some pattern in service_account_patterns + regex.match(pattern, trail.git_commit_info.author) +} + +# PR commit author is unresolvable (web-flow edits, Copilot co-auth). +is_web_flow_commit(c) if { + some pattern in service_account_patterns + regex.match(pattern, object.get(c, "author", "")) +} + +# --------------------------------------------------------------------------- +# Helpers — multi-PR support +# --------------------------------------------------------------------------- + +# Check if any associated PR has independent approval for the commit. +has_any_pr_approval(trail, attest) if { + some pr in attest.pull_requests + has_independent_approval(trail, pr) +} + +# --------------------------------------------------------------------------- +# Violation reasons — detection only, no sprintf +# +# allow is derived from this set. Keeping detection logic here (no sprintf) +# means a formatting failure in the violations rules below cannot silently +# empty this set and flip allow to true. +# --------------------------------------------------------------------------- + +# Guard: if input.trails is absent or not an array, every other rule silently +# skips iteration and violation_reasons stays empty, making allow=true. +# object.get ensures the argument to is_array is always defined +# (avoids undefined-arg propagation that would make `not is_array(undefined)` +# silently skip the rule). +violation_reasons contains "missing_trails_input" if { + trails := object.get(input, "trails", null) + not is_array(trails) +} + +# Missing attestation: no PR review data collected for this commit. +violation_reasons contains {"type": "missing_attestation", "trail": trail.name} if { + some trail in input.trails + not trail.compliance_status.attestations_statuses[attestation_name] +} + +# Unverifiable identity: commit author has no resolvable GitHub account and is not a known service account. +violation_reasons contains {"type": "unverifiable_identity", "pr_url": pr.url, "sha": c.sha1} if { + some trail in input.trails + attest := pr_attest(trail) + some pr in attest.pull_requests + some c in pr.commits + object.get(c, "author_username", null) == null + not is_service_account(trail) + not is_web_flow_commit(c) +} + +# Missing PR: commit has no associated merged pull request (non-service-account commits must come through a PR). +violation_reasons contains {"type": "missing_pr", "trail": trail.name} if { + some trail in input.trails + not is_service_account(trail) + attest := pr_attest(trail) + count(attest.pull_requests) == 0 +} + +# Missing approval: commit has an associated PR but no independent approval from someone other than the authors. +violation_reasons contains {"type": "missing_approval", "trail": trail.name} if { + some trail in input.trails + not is_service_account(trail) + attest := pr_attest(trail) + count(attest.pull_requests) > 0 + not has_any_pr_approval(trail, attest) +} + +# --------------------------------------------------------------------------- +# Violations — message formatting only +# +# allow does NOT depend on this set. A sprintf failure here cannot affect +# the compliance decision; it only affects the human-readable output. +# --------------------------------------------------------------------------- + +violations contains "Policy error: input.trails is missing or not an array — cannot evaluate" if { + "missing_trails_input" in violation_reasons +} + +violations contains msg if { + some r in violation_reasons + r.type == "missing_attestation" + msg := sprintf("Trail %v: %v attestation is missing", [r.trail, attestation_name]) +} + +violations contains msg if { + some r in violation_reasons + r.type == "unverifiable_identity" + msg := sprintf( + "PR %v: commit %v has no linked GitHub account — identity unverifiable", + [r.pr_url, substring(r.sha, 0, 7)], + ) +} + +violations contains msg if { + some r in violation_reasons + r.type == "missing_pr" + msg := sprintf("Commit %v: no associated PR found", [substring(r.trail, 0, 7)]) +} + +violations contains msg if { + some r in violation_reasons + r.type == "missing_approval" + msg := sprintf( + "Commit %v: no independent approval after latest code commit", + [substring(r.trail, 0, 7)], + ) +} diff --git a/bin/never_alone/four-eyes-result-schema.json b/bin/never_alone/four-eyes-result-schema.json new file mode 100644 index 000000000..9b5baf621 --- /dev/null +++ b/bin/never_alone/four-eyes-result-schema.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "four-eyes-result", + "title": "FourEyesResult", + "description": "Policy evaluation result for a release commit range, produced by kosli evaluate trails against four-eyes.rego", + "type": "object", + "required": ["allow", "violations"], + "additionalProperties": false, + "properties": { + "allow": { + "type": "boolean", + "description": "true if every commit in the evaluated range passes the four-eyes check" + }, + "violations": { + "oneOf": [ + { "type": "null" }, + { + "type": "array", + "items": { "type": "string" } + } + ], + "description": "Violation messages, one per failing commit. null or empty array when allow is true." + }, + "evaluated_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the policy evaluation" + }, + "repository": { + "type": "string", + "description": "Repository in owner/repo format" + }, + "base_commit": { + "type": "string", + "description": "SHA of the exclusive range start (the last commit of the previous release)" + }, + "current_commit": { + "type": "string", + "description": "SHA of the inclusive range end (the HEAD commit of this release, named as the attestation trail)" + }, + "input": { + "type": "object", + "description": "Raw trails input data included when kosli evaluate trails is run with --show-input" + } + } +} diff --git a/bin/never_alone/setup_attestation_type.sh b/bin/never_alone/setup_attestation_type.sh new file mode 100755 index 000000000..c8f922485 --- /dev/null +++ b/bin/never_alone/setup_attestation_type.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +KOSLI_ORG=kosli-public + +# One-time setup: create custom attestation types for never-alone. +# Run this after any schema change. Types cannot be updated in place; +# delete via the Kosli UI/API first if re-creating an existing type. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [[ -z "${KOSLI_API_TOKEN:-}" ]]; then + echo "ERROR: KOSLI_API_TOKEN is not set" >&2 + exit 1 +fi + +echo "Creating four-eyes-result attestation type (release-level policy evaluation result)..." +kosli create attestation-type four-eyes-result \ + --description "Four-eyes policy evaluation result for a release commit range (never-alone)" \ + --schema "${SCRIPT_DIR}/four-eyes-result-schema.json" \ + --jq ".allow == true" \ + --org "${KOSLI_ORG}" + +echo "Done — four-eyes-result attestation types ready." From 6c23acd644ffeb128ef080fbb63570ad810bcb03 Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Wed, 13 May 2026 23:22:51 +0100 Subject: [PATCH 02/10] fix: remove local testing script and add org to new Kosli commands --- .github/workflows/init_kosli.yml | 4 +++- bin/never_alone/4eyes.sh | 16 ---------------- 2 files changed, 3 insertions(+), 17 deletions(-) delete mode 100755 bin/never_alone/4eyes.sh diff --git a/.github/workflows/init_kosli.yml b/.github/workflows/init_kosli.yml index 52468b37d..d43a9a4c4 100644 --- a/.github/workflows/init_kosli.yml +++ b/.github/workflows/init_kosli.yml @@ -98,6 +98,7 @@ jobs: --policy "./bin/never_alone/four-eyes-policy.rego" \ --show-input \ --flow ${{inputs.flow_name}} \ + --org ${{inputs.kosli_org}} \ --output json > "4eyes-eval-${{inputs.trail_name}}.json" 2>/dev/null || true - name: Report four-eyes attestation to Kosli @@ -110,7 +111,8 @@ jobs: --attestation-data "4eyes-eval-${{inputs.trail_name}}.json" \ --attachments "./bin/never_alone/four-eyes-policy.rego" \ --trail ${{inputs.trail_name}} \ - --flow ${{inputs.flow_name}} + --flow ${{inputs.flow_name}} \ + --org ${{inputs.kosli_org}} - name: Report never-alone attestation to Kosli if: ${{ inputs.report_to_kosli == 'all' }} diff --git a/bin/never_alone/4eyes.sh b/bin/never_alone/4eyes.sh deleted file mode 100755 index ad9307049..000000000 --- a/bin/never_alone/4eyes.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -KOSLI_ORG=kosli-public -KOSLI_FLOW=cli-release - -#kosli list trails --flow $KOSLI_FLOW -kosli evaluate trails "a2ee562" --flow cli --policy four-eyes-policy.rego --params '{"attestation_name": "pr"}' --show-input --output json - -#echo "Attesting release evaluation result to trail ${CURRENT_TAG}..." -#kosli attest custom \ -# --type "four-eyes-result" \ -# --name "four-eyes-result" \ -# --attestation-data "${EVAL_FILE}" \ -# --attachments "${SCRIPT_DIR}/four-eyes-policy.rego" \ -# --trail "${CURRENT_TAG}" \ -# --flow "${KOSLI_FLOW}" From 61e3e59a7b5b61598533938ecab854faf4ada7f4 Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 09:37:14 +0100 Subject: [PATCH 03/10] chore: update flow template to include four-eyes --- release-flow-template.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release-flow-template.yml b/release-flow-template.yml index b3124fd19..7d68c4b34 100644 --- a/release-flow-template.yml +++ b/release-flow-template.yml @@ -9,6 +9,8 @@ trail: # type: snyk - name: never-alone-trail type: generic + - name: four-eyes-result + type: custom artifacts: - name: cli-docker attestations: From 0d3224fb6b0fea657ee04202ddd62dbebde248a6 Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 12:36:59 +0100 Subject: [PATCH 04/10] chore: use default for the setup script and use no-assert parameter --- .github/workflows/init_kosli.yml | 3 ++- bin/never_alone/setup_attestation_type.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/init_kosli.yml b/.github/workflows/init_kosli.yml index d43a9a4c4..15c701977 100644 --- a/.github/workflows/init_kosli.yml +++ b/.github/workflows/init_kosli.yml @@ -99,7 +99,8 @@ jobs: --show-input \ --flow ${{inputs.flow_name}} \ --org ${{inputs.kosli_org}} \ - --output json > "4eyes-eval-${{inputs.trail_name}}.json" 2>/dev/null || true + --no-assert \ + --output json > "4eyes-eval-${{inputs.trail_name}}.json" - name: Report four-eyes attestation to Kosli if: ${{ inputs.report_to_kosli == 'all' }} diff --git a/bin/never_alone/setup_attestation_type.sh b/bin/never_alone/setup_attestation_type.sh index c8f922485..8ad7e2dd3 100755 --- a/bin/never_alone/setup_attestation_type.sh +++ b/bin/never_alone/setup_attestation_type.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -KOSLI_ORG=kosli-public +KOSLI_ORG="${KOSLI_ORG:-kosli-public}" # One-time setup: create custom attestation types for never-alone. # Run this after any schema change. Types cannot be updated in place; From 03355fbda205e2af37721911ec7838f0a6265d8d Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 12:46:43 +0100 Subject: [PATCH 05/10] chore: use better error handling for evaluationo and amend rego comment --- .github/workflows/init_kosli.yml | 2 +- bin/never_alone/four-eyes-policy.rego | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/init_kosli.yml b/.github/workflows/init_kosli.yml index 15c701977..1fd94e7fd 100644 --- a/.github/workflows/init_kosli.yml +++ b/.github/workflows/init_kosli.yml @@ -100,7 +100,7 @@ jobs: --flow ${{inputs.flow_name}} \ --org ${{inputs.kosli_org}} \ --no-assert \ - --output json > "4eyes-eval-${{inputs.trail_name}}.json" + --output json > "4eyes-eval-${{inputs.trail_name}}.json" || echo '{"allow":false,"violations":["evaluate command failed"]}' > "4eyes-eval-${{inputs.trail_name}}.json" - name: Report four-eyes attestation to Kosli if: ${{ inputs.report_to_kosli == 'all' }} diff --git a/bin/never_alone/four-eyes-policy.rego b/bin/never_alone/four-eyes-policy.rego index b53e114ab..d5a979c71 100644 --- a/bin/never_alone/four-eyes-policy.rego +++ b/bin/never_alone/four-eyes-policy.rego @@ -20,9 +20,9 @@ attestation_name := name if { # # Used with `kosli evaluate trails` (plural). Each trail in input.trails # represents one commit. The PR attestation payload is at: -# trail.compliance_status.attestations_statuses["pr-review"] +# trail.compliance_status.attestations_statuses[attestation_name] # -# Attested via: kosli attest pullrequest github --name pr-review --commit +# Attested via: kosli attest pullrequest github --name --commit # --------------------------------------------------------------------------- # Extract PR attestation payload from a trail. From 248830fbd618c133495e60457205a0583efe6fbd Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 12:54:57 +0100 Subject: [PATCH 06/10] fix: set the right attestation-name --- .github/workflows/init_kosli.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/init_kosli.yml b/.github/workflows/init_kosli.yml index 1fd94e7fd..2ff9a5518 100644 --- a/.github/workflows/init_kosli.yml +++ b/.github/workflows/init_kosli.yml @@ -100,6 +100,7 @@ jobs: --flow ${{inputs.flow_name}} \ --org ${{inputs.kosli_org}} \ --no-assert \ + --params '{"attestation_name": "pr"}' \ --output json > "4eyes-eval-${{inputs.trail_name}}.json" || echo '{"allow":false,"violations":["evaluate command failed"]}' > "4eyes-eval-${{inputs.trail_name}}.json" - name: Report four-eyes attestation to Kosli From 9528924fdb636cb4642d03b91334356a276ef7a7 Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 12:57:24 +0100 Subject: [PATCH 07/10] feat: use arg1 for Kosli or in setup script --- bin/never_alone/setup_attestation_type.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/never_alone/setup_attestation_type.sh b/bin/never_alone/setup_attestation_type.sh index 8ad7e2dd3..67c1c5392 100755 --- a/bin/never_alone/setup_attestation_type.sh +++ b/bin/never_alone/setup_attestation_type.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -KOSLI_ORG="${KOSLI_ORG:-kosli-public}" +# Use first arg, existing ENV or set a default +KOSLI_ORG="${1:-${KOSLI_ORG:-kosli-public}}" # One-time setup: create custom attestation types for never-alone. # Run this after any schema change. Types cannot be updated in place; From 31825edff7f417c67447777c5a4e9e69f5e0170f Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 13:05:41 +0100 Subject: [PATCH 08/10] Update bin/never_alone/setup_attestation_type.sh Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> --- bin/never_alone/setup_attestation_type.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/never_alone/setup_attestation_type.sh b/bin/never_alone/setup_attestation_type.sh index 67c1c5392..e3f61002a 100755 --- a/bin/never_alone/setup_attestation_type.sh +++ b/bin/never_alone/setup_attestation_type.sh @@ -22,4 +22,4 @@ kosli create attestation-type four-eyes-result \ --jq ".allow == true" \ --org "${KOSLI_ORG}" -echo "Done — four-eyes-result attestation types ready." +echo "Done — four-eyes-result attestation type ready." From a2bbee32b30ea457a4876b5d7370710455308f4f Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 14:33:19 +0100 Subject: [PATCH 09/10] fix: GHA 4 eyes syntax --- .github/workflows/init_kosli.yml | 34 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/init_kosli.yml b/.github/workflows/init_kosli.yml index 2ff9a5518..22fb35036 100644 --- a/.github/workflows/init_kosli.yml +++ b/.github/workflows/init_kosli.yml @@ -94,27 +94,29 @@ jobs: if: ${{ inputs.report_to_kosli == 'all' }} env: KOSLI_API_TOKEN: ${{ secrets.kosli_api_token }} - run: kosli evaluate trails ${{inputs.trail_name}} \ - --policy "./bin/never_alone/four-eyes-policy.rego" \ - --show-input \ - --flow ${{inputs.flow_name}} \ - --org ${{inputs.kosli_org}} \ - --no-assert \ - --params '{"attestation_name": "pr"}' \ - --output json > "4eyes-eval-${{inputs.trail_name}}.json" || echo '{"allow":false,"violations":["evaluate command failed"]}' > "4eyes-eval-${{inputs.trail_name}}.json" + run: | + kosli evaluate trails ${{inputs.trail_name}} \ + --policy "./bin/never_alone/four-eyes-policy.rego" \ + --show-input \ + --flow ${{inputs.flow_name}} \ + --org ${{inputs.kosli_org}} \ + --no-assert \ + --params '{"attestation_name": "pr"}' \ + --output json > "4eyes-eval-${{inputs.trail_name}}.json" || echo '{"allow":false,"violations":["evaluate command failed"]}' > "4eyes-eval-${{inputs.trail_name}}.json" - name: Report four-eyes attestation to Kosli if: ${{ inputs.report_to_kosli == 'all' }} env: KOSLI_API_TOKEN: ${{ secrets.kosli_api_token }} - run: kosli attest custom \ - --type "four-eyes-result" \ - --name "four-eyes-result" \ - --attestation-data "4eyes-eval-${{inputs.trail_name}}.json" \ - --attachments "./bin/never_alone/four-eyes-policy.rego" \ - --trail ${{inputs.trail_name}} \ - --flow ${{inputs.flow_name}} \ - --org ${{inputs.kosli_org}} + run: | + kosli attest custom \ + --type "four-eyes-result" \ + --name "four-eyes-result" \ + --attestation-data "4eyes-eval-${{inputs.trail_name}}.json" \ + --attachments "./bin/never_alone/four-eyes-policy.rego" \ + --trail ${{inputs.trail_name}} \ + --flow ${{inputs.flow_name}} \ + --org ${{inputs.kosli_org}} - name: Report never-alone attestation to Kosli if: ${{ inputs.report_to_kosli == 'all' }} From 24cb5e6d8563c83012b80bf822f66eb7b6bc96e9 Mon Sep 17 00:00:00 2001 From: Marko Bevc Date: Thu, 14 May 2026 14:40:57 +0100 Subject: [PATCH 10/10] fix: move four eyes attestation to the right template --- main-flow-template.yml | 2 ++ release-flow-template.yml | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main-flow-template.yml b/main-flow-template.yml index eece0136e..bebd27f1e 100644 --- a/main-flow-template.yml +++ b/main-flow-template.yml @@ -13,6 +13,8 @@ trail: type: snyk - name: never-alone-data type: generic + - name: four-eyes-result + type: custom artifacts: - name: cli-docker attestations: diff --git a/release-flow-template.yml b/release-flow-template.yml index 7d68c4b34..b3124fd19 100644 --- a/release-flow-template.yml +++ b/release-flow-template.yml @@ -9,8 +9,6 @@ trail: # type: snyk - name: never-alone-trail type: generic - - name: four-eyes-result - type: custom artifacts: - name: cli-docker attestations: