diff --git a/ci-operator/config/openshift/agentic-skills/openshift-agentic-skills-main.yaml b/ci-operator/config/openshift/agentic-skills/openshift-agentic-skills-main.yaml index 3faa92e0f3a68..3c000a22afce9 100644 --- a/ci-operator/config/openshift/agentic-skills/openshift-agentic-skills-main.yaml +++ b/ci-operator/config/openshift/agentic-skills/openshift-agentic-skills-main.yaml @@ -13,14 +13,14 @@ images: FROM python-311 COPY . /src WORKDIR /src - RUN pip install cisco-ai-skill-scanner + RUN pip install "cisco-ai-skill-scanner[vertex]" skillsaw from: python-311 inputs: src: paths: - destination_dir: . source_path: /go/src/github.com/openshift/agentic-skills/. - to: skill-scanner + to: skill-tools promotion: to: - name: "5.0" @@ -39,14 +39,16 @@ resources: cpu: 100m memory: 200Mi tests: -- as: eval - commands: | - skill-scanner scan-all . --recursive --check-overlap --format json \ - --fail-on-severity medium \ - --output "${ARTIFACT_DIR}/skill-scanner-report.json" - container: - from: skill-scanner - skip_if_only_changed: ^(README\.md|OWNERS|LICENSE|AGENTS\.md|CLAUDE\.md|\.gitignore)$ +- as: lint + skip_if_only_changed: ^(README\.md|OWNERS|LICENSE|\.gitignore)$ + steps: + test: + - ref: openshift-harness-lint +- as: security-scan + skip_if_only_changed: ^(README\.md|OWNERS|LICENSE|\.gitignore)$ + steps: + test: + - ref: openshift-harness-security-scan zz_generated_metadata: branch: main org: openshift diff --git a/ci-operator/jobs/openshift/agentic-skills/openshift-agentic-skills-main-presubmits.yaml b/ci-operator/jobs/openshift/agentic-skills/openshift-agentic-skills-main-presubmits.yaml index 19d0c5b93b586..fb9e6878db7d0 100644 --- a/ci-operator/jobs/openshift/agentic-skills/openshift-agentic-skills-main-presubmits.yaml +++ b/ci-operator/jobs/openshift/agentic-skills/openshift-agentic-skills-main-presubmits.yaml @@ -1,26 +1,82 @@ presubmits: openshift/agentic-skills: + - agent: kubernetes + always_run: true + branches: + - ^main$ + - ^main- + cluster: build04 + context: ci/prow/images + decorate: true + labels: + ci.openshift.io/generator: prowgen + pj-rehearse.openshift.io/can-be-rehearsed: "true" + name: pull-ci-openshift-agentic-skills-main-images + rerun_command: /test images + spec: + containers: + - args: + - --gcs-upload-secret=/secrets/gcs/service-account.json + - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --report-credentials-file=/etc/report/credentials + - --target=[images] + - --target=[release:latest] + command: + - ci-operator + image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest + imagePullPolicy: Always + name: "" + resources: + requests: + cpu: 10m + volumeMounts: + - mountPath: /secrets/gcs + name: gcs-credentials + readOnly: true + - mountPath: /secrets/manifest-tool + name: manifest-tool-local-pusher + readOnly: true + - mountPath: /etc/pull-secret + name: pull-secret + readOnly: true + - mountPath: /etc/report + name: result-aggregator + readOnly: true + serviceAccountName: ci-operator + volumes: + - name: manifest-tool-local-pusher + secret: + secretName: manifest-tool-local-pusher + - name: pull-secret + secret: + secretName: registry-pull-credentials + - name: result-aggregator + secret: + secretName: result-aggregator + trigger: (?m)^/test( | .* )images,?($|\s.*) - agent: kubernetes always_run: false branches: - ^main$ - ^main- cluster: build04 - context: ci/prow/eval + context: ci/prow/lint decorate: true labels: ci.openshift.io/generator: prowgen pj-rehearse.openshift.io/can-be-rehearsed: "true" - name: pull-ci-openshift-agentic-skills-main-eval - rerun_command: /test eval - skip_if_only_changed: ^(README\.md|OWNERS|LICENSE|AGENTS\.md|CLAUDE\.md|\.gitignore)$ + name: pull-ci-openshift-agentic-skills-main-lint + rerun_command: /test lint + skip_if_only_changed: ^(README\.md|OWNERS|LICENSE|\.gitignore)$ spec: containers: - args: - --gcs-upload-secret=/secrets/gcs/service-account.json - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials - --report-credentials-file=/etc/report/credentials - - --target=eval + - --secret-dir=/secrets/ci-pull-credentials + - --target=lint command: - ci-operator env: @@ -38,6 +94,12 @@ presubmits: requests: cpu: 10m volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true - mountPath: /secrets/gcs name: gcs-credentials readOnly: true @@ -52,6 +114,15 @@ presubmits: readOnly: true serviceAccountName: ci-operator volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials - name: manifest-tool-local-pusher secret: secretName: manifest-tool-local-pusher @@ -61,37 +132,53 @@ presubmits: - name: result-aggregator secret: secretName: result-aggregator - trigger: (?m)^/test( | .* )eval,?($|\s.*) + trigger: (?m)^/test( | .* )lint,?($|\s.*) - agent: kubernetes - always_run: true + always_run: false branches: - ^main$ - ^main- cluster: build04 - context: ci/prow/images + context: ci/prow/security-scan decorate: true labels: ci.openshift.io/generator: prowgen pj-rehearse.openshift.io/can-be-rehearsed: "true" - name: pull-ci-openshift-agentic-skills-main-images - rerun_command: /test images + name: pull-ci-openshift-agentic-skills-main-security-scan + rerun_command: /test security-scan + skip_if_only_changed: ^(README\.md|OWNERS|LICENSE|\.gitignore)$ spec: containers: - args: - --gcs-upload-secret=/secrets/gcs/service-account.json - --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson + - --lease-server-credentials-file=/etc/boskos/credentials - --report-credentials-file=/etc/report/credentials - - --target=[images] - - --target=[release:latest] + - --secret-dir=/secrets/ci-pull-credentials + - --target=security-scan command: - ci-operator + env: + - name: HTTP_SERVER_IP + valueFrom: + fieldRef: + fieldPath: status.podIP image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest imagePullPolicy: Always name: "" + ports: + - containerPort: 8080 + name: http resources: requests: cpu: 10m volumeMounts: + - mountPath: /etc/boskos + name: boskos + readOnly: true + - mountPath: /secrets/ci-pull-credentials + name: ci-pull-credentials + readOnly: true - mountPath: /secrets/gcs name: gcs-credentials readOnly: true @@ -106,6 +193,15 @@ presubmits: readOnly: true serviceAccountName: ci-operator volumes: + - name: boskos + secret: + items: + - key: credentials + path: credentials + secretName: boskos-credentials + - name: ci-pull-credentials + secret: + secretName: ci-pull-credentials - name: manifest-tool-local-pusher secret: secretName: manifest-tool-local-pusher @@ -115,4 +211,4 @@ presubmits: - name: result-aggregator secret: secretName: result-aggregator - trigger: (?m)^/test( | .* )images,?($|\s.*) + trigger: (?m)^/test( | .* )security-scan,?($|\s.*) diff --git a/ci-operator/step-registry/openshift/harness/OWNERS b/ci-operator/step-registry/openshift/harness/OWNERS new file mode 100644 index 0000000000000..26b732e26081c --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/OWNERS @@ -0,0 +1,12 @@ +approvers: +- bryan-cox +- cblecker +- Cali0707 +- enxebre +- stbenjam +reviewers: +- bryan-cox +- cblecker +- Cali0707 +- enxebre +- stbenjam diff --git a/ci-operator/step-registry/openshift/harness/lint/OWNERS b/ci-operator/step-registry/openshift/harness/lint/OWNERS new file mode 100644 index 0000000000000..26b732e26081c --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/lint/OWNERS @@ -0,0 +1,12 @@ +approvers: +- bryan-cox +- cblecker +- Cali0707 +- enxebre +- stbenjam +reviewers: +- bryan-cox +- cblecker +- Cali0707 +- enxebre +- stbenjam diff --git a/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-commands.sh b/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-commands.sh new file mode 100644 index 0000000000000..65d0ecdf90e55 --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-commands.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -euo pipefail + +echo "Running skillsaw linter..." +skillsaw -v diff --git a/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-ref.metadata.json b/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-ref.metadata.json new file mode 100644 index 0000000000000..6a447cd4eea86 --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-ref.metadata.json @@ -0,0 +1,19 @@ +{ + "path": "openshift/harness/lint/openshift-harness-lint-ref.yaml", + "owners": { + "approvers": [ + "bryan-cox", + "cblecker", + "Cali0707", + "enxebre", + "stbenjam" + ], + "reviewers": [ + "bryan-cox", + "cblecker", + "Cali0707", + "enxebre", + "stbenjam" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-ref.yaml b/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-ref.yaml new file mode 100644 index 0000000000000..69d16434c37a2 --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/lint/openshift-harness-lint-ref.yaml @@ -0,0 +1,14 @@ +ref: + as: openshift-harness-lint + from: skill-tools + commands: openshift-harness-lint-commands.sh + resources: + requests: + cpu: 100m + memory: 100Mi + timeout: 5m0s + grace_period: 30s + documentation: |- + Runs skillsaw to lint agent skills against the agentskills.io + specification. Validates skill frontmatter, naming conventions, + directory structure, and evals format. diff --git a/ci-operator/step-registry/openshift/harness/security-scan/OWNERS b/ci-operator/step-registry/openshift/harness/security-scan/OWNERS new file mode 100644 index 0000000000000..26b732e26081c --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/security-scan/OWNERS @@ -0,0 +1,12 @@ +approvers: +- bryan-cox +- cblecker +- Cali0707 +- enxebre +- stbenjam +reviewers: +- bryan-cox +- cblecker +- Cali0707 +- enxebre +- stbenjam diff --git a/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-commands.sh b/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-commands.sh new file mode 100644 index 0000000000000..f6c5d0c7652c9 --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-commands.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +set -euo pipefail + +LLM_FLAG="" +if [[ "${USE_LLM}" == "true" ]]; then + LLM_FLAG="--use-llm" + echo "Running skill-scanner with LLM-based semantic analysis..." + echo "Model: ${SKILL_SCANNER_LLM_MODEL}" +else + echo "Running skill-scanner with static rules only (LLM disabled)..." +fi + +# shellcheck disable=SC2086 +skill-scanner scan-all . --recursive --check-overlap ${LLM_FLAG} \ + --fail-on-severity medium \ + --format json \ + --output-json "${ARTIFACT_DIR}/skill-scanner-report.json" \ + --format html \ + --output-html "${ARTIFACT_DIR}/skill-scanner-summary.html" \ + ${SCAN_ADDITIONAL_ARGS} diff --git a/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-ref.metadata.json b/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-ref.metadata.json new file mode 100644 index 0000000000000..8a702e1b3ad94 --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-ref.metadata.json @@ -0,0 +1,19 @@ +{ + "path": "openshift/harness/security-scan/openshift-harness-security-scan-ref.yaml", + "owners": { + "approvers": [ + "bryan-cox", + "cblecker", + "Cali0707", + "enxebre", + "stbenjam" + ], + "reviewers": [ + "bryan-cox", + "cblecker", + "Cali0707", + "enxebre", + "stbenjam" + ] + } +} \ No newline at end of file diff --git a/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-ref.yaml b/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-ref.yaml new file mode 100644 index 0000000000000..51d9e2eeb8a96 --- /dev/null +++ b/ci-operator/step-registry/openshift/harness/security-scan/openshift-harness-security-scan-ref.yaml @@ -0,0 +1,35 @@ +ref: + as: openshift-harness-security-scan + from: skill-tools + commands: openshift-harness-security-scan-commands.sh + credentials: + - mount_path: /var/run/claude-code-service-account + name: sa-claude-openshift-ci + namespace: test-credentials + env: + - name: GOOGLE_APPLICATION_CREDENTIALS + default: /var/run/claude-code-service-account/token + documentation: Path to the GCP service account key for Vertex AI access. + - name: SKILL_SCANNER_LLM_MODEL + default: vertex_ai/claude-sonnet-4-6 + documentation: LiteLLM model string for LLM-based semantic analysis. + - name: VERTEXAI_LOCATION + default: global + documentation: Vertex AI region for model serving. + - name: USE_LLM + default: "true" + documentation: Set to "false" to disable LLM-based semantic analysis and use only static YARA rules. + - name: SCAN_ADDITIONAL_ARGS + default: "" + documentation: Additional arguments to pass to skill-scanner. + resources: + requests: + cpu: 100m + memory: 100Mi + timeout: 10m0s + grace_period: 5m0s + documentation: |- + Runs cisco-ai-skill-scanner with LLM-based semantic analysis + (via Vertex AI / Claude Sonnet) to detect prompt injection, + data exfiltration, command injection, and other agent security + issues. Fails on medium severity findings by default.