chore(deps): update odh-llm-d-batch-gateway-apiserver-v3-5-ea-1 to 4fe5094 #12353
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: linters | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - rhoai | |
| pull_request: | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| checks: write | |
| jobs: | |
| golangci: | |
| name: golangci-lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 | |
| - name: Set up Go env | |
| uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version-file: go.mod | |
| - name: lint | |
| run: | |
| make lint | |
| kube-linter: | |
| name: kube-linter | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write # For SARIF upload | |
| steps: | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 | |
| - name: Set up Go env | |
| uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 | |
| with: | |
| go-version-file: go.mod | |
| - name: Install kube-linter | |
| run: | | |
| # Install pre-built binary from GitHub Releases (avoids supply chain risk) | |
| set -euo pipefail | |
| KUBE_LINTER_VERSION="v0.8.1" | |
| KUBE_LINTER_ASSET="kube-linter-linux.tar.gz" | |
| KUBE_LINTER_URL="https://github.com/stackrox/kube-linter/releases/download/${KUBE_LINTER_VERSION}/kube-linter-linux.tar.gz" | |
| KUBE_LINTER_SHA256="49629abaf0ae3283e9437214a2bea4bf4029008744e05471c85dd3872464f50b" | |
| curl -sSfL --max-time 300 -o "${KUBE_LINTER_ASSET}" "${KUBE_LINTER_URL}" | |
| echo "${KUBE_LINTER_SHA256} ${KUBE_LINTER_ASSET}" | sha256sum -c - | |
| tar -xzf "${KUBE_LINTER_ASSET}" kube-linter | |
| sudo mv kube-linter /usr/local/bin/ | |
| kube-linter version | |
| rm -f "${KUBE_LINTER_ASSET}" | |
| # Run kube-linter with SARIF output for GitHub Security tab integration | |
| - name: Run kube-linter (SARIF output) | |
| id: kubelinter_sarif | |
| run: | | |
| set -euo pipefail | |
| # Prepare manifests | |
| make prepare | |
| TMP_FILE=$(mktemp /tmp/kube-lint.XXXXXX.yaml) | |
| ./bin/kustomize build config/manifests > "$TMP_FILE" | |
| # Run kube-linter with SARIF format for GitHub Security tab | |
| # Redirect stderr to avoid contaminating SARIF output | |
| kube-linter lint \ | |
| --config .kube-linter.yaml \ | |
| --format sarif \ | |
| "$TMP_FILE" > kube-linter.sarif 2>kube-linter.stderr || true | |
| # Validate SARIF file before upload | |
| if [ -f kube-linter.sarif ] && [ -s kube-linter.sarif ]; then | |
| if jq -e . kube-linter.sarif >/dev/null 2>&1; then | |
| echo "✅ Valid SARIF output generated" | |
| echo "sarif_valid=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "⚠️ Invalid SARIF JSON - skipping upload" | |
| cat kube-linter.stderr || true | |
| echo "sarif_valid=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "⚠️ SARIF file empty or missing" | |
| cat kube-linter.stderr || true | |
| echo "sarif_valid=false" >> $GITHUB_OUTPUT | |
| fi | |
| rm -f "$TMP_FILE" kube-linter.stderr | |
| continue-on-error: true | |
| # Upload SARIF to GitHub Security tab | |
| - name: Upload kube-linter SARIF results | |
| if: always() && steps.kubelinter_sarif.outputs.sarif_valid == 'true' | |
| uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8 | |
| with: | |
| sarif_file: kube-linter.sarif | |
| category: kube-linter | |
| # Run kube-linter with severity-based blocking (CRITICAL/HIGH only) | |
| # MEDIUM and LOW findings are reported but don't block PRs | |
| - name: Run kube-linter (blocking check - CRITICAL/HIGH only) | |
| run: | | |
| set -euo pipefail | |
| # Prepare manifests | |
| make prepare | |
| TMP_FILE=$(mktemp /tmp/kube-lint.XXXXXX.yaml) | |
| ./bin/kustomize build config/manifests > "$TMP_FILE" | |
| # Run kube-linter with JSON output for severity filtering | |
| kube-linter lint \ | |
| --config .kube-linter.yaml \ | |
| --format json \ | |
| "$TMP_FILE" > kube-linter-pr-check.json || true | |
| # Analyze findings and block only on CRITICAL/HIGH | |
| python3 - <<'EOF' | |
| import json | |
| import sys | |
| # Severity mapping for kube-linter checks | |
| CRITICAL_CHECKS = { | |
| 'cluster-admin-role-binding', 'privileged-container', | |
| 'host-network', 'host-pid', 'host-ipc', 'docker-sock', | |
| 'access-to-create-pods', 'privilege-escalation-container', | |
| 'run-as-non-root', 'no-read-only-root-fs', 'privileged-ports' | |
| } | |
| HIGH_CHECKS = { | |
| 'access-to-secrets', 'wildcard-in-rules', 'sensitive-host-mounts', | |
| 'writable-host-mount', 'unsafe-proc-mount', 'unsafe-sysctls', | |
| 'default-service-account', 'env-var-secret', 'read-secret-from-env-var', | |
| 'drop-net-raw-capability', 'exposed-services', 'non-isolated-pod', | |
| 'ssh-port', 'latest-tag', 'no-system-group-binding' | |
| } | |
| MEDIUM_CHECKS = { | |
| 'no-liveness-probe', 'no-readiness-probe', | |
| 'unset-cpu-requirements', 'unset-memory-requirements', | |
| 'use-namespace', 'non-existent-service-account' | |
| } | |
| # Operator infrastructure RBAC that requires broad permissions | |
| # These are excluded from certain checks, but component RBAC is still validated | |
| # Uses (Kind, Name, Namespace) tuples to prevent name-only spoofing (CWE-693) | |
| OPERATOR_INFRASTRUCTURE = { | |
| # (kind, name, namespace) - None for cluster-scoped resources | |
| ('ClusterRole', 'controller-manager-role', None), | |
| ('ClusterRoleBinding', 'controller-manager-rolebinding', None), | |
| ('ClusterRole', 'opendatahub-operator-controller-manager-role', None), | |
| ('ClusterRoleBinding', 'opendatahub-operator-controller-manager-rolebinding', None), | |
| ('Deployment', 'opendatahub-operator-controller-manager', 'opendatahub-operator-system'), | |
| } | |
| # Checks to skip for operator infrastructure only | |
| OPERATOR_EXEMPT_CHECKS = { | |
| 'access-to-create-pods', # Operator deploys workload pods | |
| 'wildcard-in-rules', # Operator needs dynamic CRD management | |
| 'access-to-secrets', # Operator manages component credentials | |
| 'latest-tag', # Image tag is a kustomize placeholder (REPLACE_IMAGE), patched at build time | |
| 'non-isolated-pod', # NetworkPolicy managed at platform level (OCP/K8s network plugin) | |
| } | |
| try: | |
| with open('kube-linter-pr-check.json') as f: | |
| data = json.load(f) | |
| except FileNotFoundError: | |
| print("❌ ERROR: kube-linter output not found - failing check to prevent bypass") | |
| sys.exit(1) | |
| except json.JSONDecodeError as e: | |
| print(f"❌ ERROR: Failed to parse kube-linter JSON: {e}") | |
| print(" Failing check to prevent bypass - ensure kube-linter runs successfully") | |
| sys.exit(1) | |
| reports = data.get('Reports', []) | |
| critical_findings = [] | |
| high_findings = [] | |
| medium_findings = [] | |
| low_count = 0 | |
| filtered_count = 0 | |
| for report in reports: | |
| check_name = report.get('Check', 'unknown') | |
| obj = report.get('Object', {}).get('K8sObject', {}) | |
| obj_name = obj.get('Name', 'unknown') | |
| obj_kind = obj.get('GroupVersionKind', {}).get('Kind', 'unknown') | |
| obj_namespace = obj.get('Namespace') or None # None for cluster-scoped | |
| # Filter out operator infrastructure for exempt checks (structural identity matching) | |
| if check_name in OPERATOR_EXEMPT_CHECKS and (obj_kind, obj_name, obj_namespace) in OPERATOR_INFRASTRUCTURE: | |
| filtered_count += 1 | |
| continue | |
| if check_name in CRITICAL_CHECKS: | |
| critical_findings.append(report) | |
| elif check_name in HIGH_CHECKS: | |
| high_findings.append(report) | |
| elif check_name in MEDIUM_CHECKS: | |
| medium_findings.append(report) | |
| else: | |
| low_count += 1 | |
| # Print summary | |
| print("\n" + "="*80) | |
| print("🔍 Kube-linter PR Check Results") | |
| print("="*80) | |
| if filtered_count > 0: | |
| print(f"\nℹ️ Filtered {filtered_count} operator infrastructure findings") | |
| print(" (controller-manager RBAC exempt from pod/secret/wildcard checks)") | |
| if critical_findings: | |
| print(f"\n🔴 CRITICAL: {len(critical_findings)} findings (BLOCKING)") | |
| for finding in critical_findings: | |
| obj = finding.get('Object', {}).get('K8sObject', {}) | |
| name = obj.get('Name', 'unknown') | |
| kind = obj.get('GroupVersionKind', {}).get('Kind', 'unknown') | |
| check = finding.get('Check', 'unknown') | |
| msg = finding.get('Diagnostic', {}).get('Message', '') | |
| print(f" ❌ {kind}/{name}: {check}") | |
| print(f" {msg}") | |
| if high_findings: | |
| print(f"\n🟠 HIGH: {len(high_findings)} findings (BLOCKING)") | |
| for finding in high_findings: | |
| obj = finding.get('Object', {}).get('K8sObject', {}) | |
| name = obj.get('Name', 'unknown') | |
| kind = obj.get('GroupVersionKind', {}).get('Kind', 'unknown') | |
| check = finding.get('Check', 'unknown') | |
| msg = finding.get('Diagnostic', {}).get('Message', '') | |
| print(f" ❌ {kind}/{name}: {check}") | |
| print(f" {msg}") | |
| if medium_findings: | |
| print(f"\n🟡 MEDIUM: {len(medium_findings)} findings (non-blocking)") | |
| for finding in medium_findings: | |
| obj = finding.get('Object', {}).get('K8sObject', {}) | |
| name = obj.get('Name', 'unknown') | |
| kind = obj.get('GroupVersionKind', {}).get('Kind', 'unknown') | |
| check = finding.get('Check', 'unknown') | |
| msg = finding.get('Diagnostic', {}).get('Message', '') | |
| print(f" ⚠️ {kind}/{name}: {check}") | |
| print(f" {msg}") | |
| if low_count > 0: | |
| print(f"\n🔵 LOW: {low_count} findings (non-blocking)") | |
| print(" ℹ️ See SARIF results in Security tab for details") | |
| # Block PR only on CRITICAL or HIGH | |
| if critical_findings or high_findings: | |
| print("\n" + "="*80) | |
| print("❌ PR BLOCKED: Fix CRITICAL/HIGH findings to proceed") | |
| print("="*80) | |
| sys.exit(1) | |
| elif medium_findings or low_count > 0: | |
| print("\n" + "="*80) | |
| print("✅ PR CHECK PASSED (MEDIUM/LOW findings don't block)") | |
| print("📋 Please address these findings in a follow-up PR") | |
| print("="*80) | |
| sys.exit(0) | |
| else: | |
| print("\n" + "="*80) | |
| print("✅ ALL CHECKS PASSED - No kube-linter findings") | |
| print("="*80) | |
| sys.exit(0) | |
| EOF | |
| rm -f "$TMP_FILE" kube-linter-pr-check.json |