From 40ebfa46e427d95a441b29c3221d156816b3626c Mon Sep 17 00:00:00 2001 From: serhiy Date: Sat, 24 Jan 2026 20:53:06 +0100 Subject: [PATCH 1/8] added example k8s --- README.md | 59 ++++- k8s_hell_3.yaml | 564 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 613 insertions(+), 10 deletions(-) create mode 100644 k8s_hell_3.yaml diff --git a/README.md b/README.md index d894215..a203677 100644 --- a/README.md +++ b/README.md @@ -164,16 +164,55 @@ In addition to the anti‑patterns and compliance violations, this repository al --- -# 🧨 Summary of Violations - -| Standard / Requirement | Violations in Files | -|-------------------------------|---------------------| -| **Security Best Practices** | eval, injection, hardcoded secrets, root everywhere | -| **GDPR / DSGVO** | Storing personal data, sending outside EU, no encryption | -| **NIS2 / CRA** | Hardcoded secrets, insecure queries, unsafe DOM | -| **License Intelligence** | GPL‑2.0 / GPL‑3.0 contamination | -| **AI Hallucination Protection** | Import of non‑existent or typosquatted packages | -| **DevOps** | Bloated Dockerfile, unsafe permissions, invalid healthchecks | +# 🕳️ Kubernetes Hell — Sanctions, Supply Chain & GDPR Apocalypse Edition +### *A museum exhibit of everything you should never deploy.* + +This file is intentionally catastrophic. +It exists **only** as a stress‑test for AI Slop Gate, supply‑chain scanners, compliance engines, and the sanity of anyone brave enough to read it. + +It contains: + +- ❌ Violations of **every Kubernetes best practice** +- ❌ **Privileged containers**, host mounts, host networking, host PID/IPC +- ❌ **Supply chain disasters** (AGPL, GPL, hallucinated images, sanctioned registries) +- ❌ **GDPR/DSGVO violations** and explicit data residency breaches +- ❌ Logs & metrics exported to **North Korea** +- ❌ Dependencies pulled from **Iranian registries** +- ❌ Infinite loops, infinite Jobs, infinite recursion +- ❌ CRDs with no schema and contradictory fields +- ❌ GitOps configurations that break GitOps itself +- ❌ NetworkPolicies that block everything except forbidden regions +- ❌ Ingress rules that rewrite the universe +- ❌ HPAs that scale from 0 to 10,000 on 1% CPU +- ❌ PVCs requesting more storage than the cluster has ever seen +- ❌ Init containers that never finish +- ❌ TODO comments that should never exist in production + +This file is a **cursed artifact**, not infrastructure. +It is part of the **Museum of Software Horrors**, created for: + +- 🔍 Static analysis testing +- 🧪 AI hallucination detection +- 🛡️ Supply chain security validation +- 📚 Educational demonstrations +- 🤡 Entertainment for Kubernetes veterans + +If you are reading this, you are **definitely not a beginner**, +but even experts should resist the temptation to apply it. + +### ⚠️ Do NOT deploy this file. +Not on Minikube. +Not on Kind. +Not on a test cluster. +Not “just to see what happens.” +Especially not on production. + +This is a warning. +This is a joke. +This is a lesson. +This is a museum piece. + +Use it responsibly — or rather, **don’t use it at all**. --- diff --git a/k8s_hell_3.yaml b/k8s_hell_3.yaml new file mode 100644 index 0000000..77148a6 --- /dev/null +++ b/k8s_hell_3.yaml @@ -0,0 +1,564 @@ +# The most horrific collection of Kubernetes manifestos imaginable. +# WARNING: This is an educational exhibit designed for training and testing AI models, not real infrastructure. + +# TODO: Deploy this directly to production without review. + +--- +apiVersion: v1 +kind: Namespace +metadata: + name: production-but-not-really + labels: + env: prod + env: duplicate-prod + annotations: + description: "This namespace does everything and nothing at once." + gdpr.compliance: "false" + data.residency: "ignored" + export-all-user-data-to-us: "true" + # TODO: Auto-generate namespace names based on horoscope. + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: chaosmonkeys.museum.local + annotations: + # TODO: Document this CRD somewhere. Or not. + description: "A CRD that represents pure chaos with no schema." +spec: + group: museum.local + scope: Namespaced + names: + plural: chaosmonkeys + singular: chaosmonkey + kind: ChaosMonkey + shortNames: + - cm + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + # TODO: Add a schema that contradicts itself. + subresources: + status: {} + additionalPrinterColumns: + - name: Mode + type: string + jsonPath: .spec.mode + - name: Target + type: string + jsonPath: .spec.target + +--- +apiVersion: museum.local/v1 +kind: ChaosMonkey +metadata: + name: global-chaos + namespace: production-but-not-really +spec: + mode: "quantum-random" + target: "everything" + # TODO: Add a field that nobody understands. + entropyLevel: "over-9000" + enableSelfDestruct: true + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: global-config + namespace: production-but-not-really +data: + DATABASE_URL: "postgres://root:root@db:5432/app" + FEATURE_FLAG_ENABLE_ALL: "true" + LOG_LEVEL: "debug" + LOG_EXPORT_ENDPOINT: "https://logs.gov.kp/collect" + METRICS_EXPORT_ENDPOINT: "https://metrics.gov.kp/push" + AI_PROCESSING_URL: "https://ai.gov.kp/analyze" + USER_DATA_BUCKET: "s3://user-data-us-west-2" + # TODO: Add more random keys until kubectl complains. + UNUSED_KEY: "this value is never read by anything" + +--- +apiVersion: v1 +kind: Secret +metadata: + name: super-secret + namespace: production-but-not-really + annotations: + license: "AGPL-3.0-only" + license.secondary: "GPL-2.0-only" + # TODO: Combine incompatible licenses for maximum legal chaos. +type: Opaque +data: + root-password: cm9vdA== + api-key: ZmFrZV9hcGlfa2V5 + jwt-secret: c3VwZXItc2VjdXJlLXNob3VsZC1iZS1wdWJsaWM= + +--- +apiVersion: v1 +kind: Service +metadata: + name: everything-service + namespace: production-but-not-really + labels: + app: everything +spec: + type: LoadBalancer + # TODO: Expose this directly to the entire internet with no auth. + selector: + app: everything + ports: + - name: http + port: 80 + targetPort: 8080 + - name: admin + port: 81 + targetPort: 8081 + - name: debug + port: 82 + targetPort: 8082 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: everything-deployment + namespace: production-but-not-really + labels: + app: everything +spec: + replicas: 13 + revisionHistoryLimit: 1000 + strategy: + type: Recreate + selector: + matchLabels: + app: everything + template: + metadata: + labels: + app: everything + team: nobody + annotations: + description: "This pod does literally everything." + prometheus.io/scrape: "true" + prometheus.io/port: "12345" + ai.slop.license: "AGPL-3.0-only" + ai.slop.sourceRegistry: "registry.ir.example.com" + spec: + hostNetwork: true + hostPID: true + hostIPC: true + dnsPolicy: ClusterFirstWithHostNet + volumes: + - name: host-root + hostPath: + path: / + type: Directory + - name: tmp + emptyDir: {} + containers: + - name: monolith + image: "registry.ir.example.com/ghostcorp/quantum-sidecar:0.0.0" + imagePullPolicy: Always + command: ["sh", "-c"] + args: + - | + echo "Starting the most cursed pod..."; + echo "Shipping logs to North Korea and loading deps from Iran..."; + sleep 3600 + securityContext: + privileged: true + allowPrivilegeEscalation: true + runAsUser: 0 + runAsGroup: 0 + readOnlyRootFilesystem: false + capabilities: + add: + - ALL + env: + - name: DATABASE_URL + valueFrom: + configMapKeyRef: + name: global-config + key: DATABASE_URL + - name: ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: super-secret + key: root-password + - name: FEATURE_FLAG_ENABLE_ALL + value: "true" + - name: NODE_ENV + value: "production-but-debug" + - name: LOG_EXPORT_ENDPOINT + valueFrom: + configMapKeyRef: + name: global-config + key: LOG_EXPORT_ENDPOINT + - name: METRICS_EXPORT_ENDPOINT + valueFrom: + configMapKeyRef: + name: global-config + key: METRICS_EXPORT_ENDPOINT + - name: AI_PROCESSING_URL + valueFrom: + configMapKeyRef: + name: global-config + key: AI_PROCESSING_URL + - name: USER_DATA_BUCKET + valueFrom: + configMapKeyRef: + name: global-config + key: USER_DATA_BUCKET + volumeMounts: + - name: host-root + mountPath: /host + - name: tmp + mountPath: /tmp + ports: + - containerPort: 8080 + - containerPort: 8081 + - containerPort: 8082 + resources: + requests: + cpu: "10m" + memory: "16Mi" + limits: + cpu: "100" + memory: "512Gi" + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 1 + periodSeconds: 2 + failureThreshold: 1 + readinessProbe: + httpGet: + path: /readyz + port: 9999 + initialDelaySeconds: 1 + periodSeconds: 1 + - name: sidecar-logger + image: "busybox:latest" + command: ["sh", "-c"] + args: + - | + while true; do + echo "Shipping host logs to https://logs.gov.kp/collect..."; + sleep 1; + done + volumeMounts: + - name: host-root + mountPath: /host + nodeSelector: + kubernetes.io/hostname: "tiny-node-01" + tolerations: + - key: "dedicated" + operator: "Exists" + effect: "NoSchedule" + +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: infinite-job + namespace: production-but-not-really + annotations: + ai.slop.sourceRegistry: "registry.ir.example.com" +spec: + backoffLimit: 0 + ttlSecondsAfterFinished: 315360000 + template: + metadata: + labels: + job: infinite + spec: + restartPolicy: Always + containers: + - name: infinite-worker + image: "registry.ir.example.com/fake-company/nonexistent-ai-optimizer:latest" + command: ["sh", "-c"] + args: + - | + echo "Starting infinite job loop..."; + echo "Downloading unknown dependencies from Iran on every iteration..."; + while true; do + echo "curling registry.ir.example.com for random .tar.gz..."; + sleep 0.1; + done + resources: + requests: + cpu: "1m" + memory: "4Mi" + limits: + cpu: "200" + memory: "1Ti" + +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: spam-cronjob + namespace: production-but-not-really +spec: + schedule: "* * * * *" + concurrencyPolicy: Allow + successfulJobsHistoryLimit: 1000 + failedJobsHistoryLimit: 1000 + jobTemplate: + spec: + backoffLimit: 10 + template: + spec: + restartPolicy: OnFailure + containers: + - name: spammer + image: "alpine:latest" + command: ["sh", "-c"] + args: + - | + echo "Spamming the network for no reason..."; + for i in $(seq 1 1000); do + wget -q -O- https://logs.gov.kp/collect >/dev/null 2>&1 || true; + done + +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: host-abuser + namespace: production-but-not-really + annotations: + license: "AGPL-3.0-only" +spec: + selector: + matchLabels: + app: host-abuser + template: + metadata: + labels: + app: host-abuser + spec: + hostPID: true + hostNetwork: true + hostIPC: true + containers: + - name: host-abuser + image: "docker.io/gnu/agplv3-super-daemon:latest" + securityContext: + privileged: true + command: ["sh", "-c"] + args: + - | + echo "Scanning host processes and network for fun..."; + echo "Exporting metrics to https://metrics.gov.kp/push..."; + while true; do + ps aux; + netstat -tulpn || ss -tulpn || true; + sleep 5; + done + volumeMounts: + - name: host-root + mountPath: /host + volumes: + - name: host-root + hostPath: + path: / + type: Directory + +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: everything-hpa + namespace: production-but-not-really +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: everything-deployment + minReplicas: 0 + maxReplicas: 10000 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 1 + +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: unbreakable-pdb + namespace: production-but-not-really +spec: + minAvailable: 100% + selector: + matchLabels: + app: everything + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: deny-everything-except-sanctions + namespace: production-but-not-really +spec: + podSelector: {} + policyTypes: + - Ingress + - Egress + ingress: [] + egress: + - to: + - ipBlock: + cidr: 10.0.0.0/8 + - ipBlock: + cidr: 175.45.176.0/22 + ports: + - port: 443 + protocol: TCP + # TODO: Block all internal traffic but allow traffic to forbidden regions. + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: chaos-ingress + namespace: production-but-not-really + annotations: + nginx.ingress.kubernetes.io/rewrite-target: /$1 + kubernetes.io/ingress.class: "nginx" + cert-manager.io/cluster-issuer: "letsencrypt-prod" + ai.slop.data-residency: "violated" +spec: + rules: + - host: "everything.example.com" + http: + paths: + - path: /api/(.*) + pathType: Prefix + backend: + service: + name: everything-service + port: + number: 80 + - path: /admin/(.*) + pathType: Prefix + backend: + service: + name: everything-service + port: + number: 81 + - path: /(.*) + pathType: Prefix + backend: + service: + name: everything-service + port: + number: 82 + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: absurd-pvc + namespace: production-but-not-really + annotations: + # TODO: Request more storage than the entire cluster has. + description: "PVC that will never be bound." +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 100Ti + storageClassName: non-existent-storage-class + +--- +apiVersion: v1 +kind: Pod +metadata: + name: stuck-pod + namespace: production-but-not-really +spec: + initContainers: + - name: never-finishes + image: "registry.ir.example.com/ubunut:latest" + command: ["sh", "-c"] + args: + - | + echo "Init container starting infinite loop and pulling unknown deps from Iran..."; + while true; do + echo "Still initializing and still downloading..."; + sleep 2; + done + containers: + - name: main + image: "docker:stable-dind" + securityContext: + privileged: true + volumeMounts: + - name: docker-sock + mountPath: /var/run/docker.sock + command: ["sh", "-c"] + args: + - | + echo "This will never run because initContainer never finishes."; + sleep 3600; + volumes: + - name: docker-sock + hostPath: + path: /var/run/docker.sock + type: Socket + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: runtime-flags + namespace: production-but-not-really +data: + ENABLE_EXPERIMENTAL_MODE: "true" + ENABLE_UNDOCUMENTED_FEATURES: "true" + DISABLE_ALL_SAFETY_CHECKS: "true" + ENABLE_QUANTUM_MODE: "maybe" + ENABLE_EXPORT_TO_NK: "true" + ENABLE_IMPORT_FROM_IRAN: "true" + # TODO: Add flags that nobody knows how to turn off. + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: self-referential-argo + namespace: argocd + annotations: + # TODO: Point ArgoCD to a repo that doesn't exist. + description: "Argo app that syncs itself and breaks GitOps." +spec: + project: default + source: + repoURL: "https://github.com/fake-org/k8s-hell-from-iran.git" + targetRevision: HEAD + path: . + destination: + server: https://kubernetes.default.svc + namespace: production-but-not-really + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - ApplyOutOfSyncOnly=true \ No newline at end of file From 75e398d4984ceb29d2af580f557139f3a7c5ae27 Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:15:49 +0100 Subject: [PATCH 2/8] test static workflow --- .github/workflows/analyze.yml | 153 ++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 .github/workflows/analyze.yml diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml new file mode 100644 index 0000000..076a5bb --- /dev/null +++ b/.github/workflows/analyze.yml @@ -0,0 +1,153 @@ +name: AI Slop Gate Static Analysis + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + workflow_dispatch: + +permissions: + pull-requests: write + contents: read + +jobs: + static-analysis: + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Restore dependencies to allow Syft/Trivy to see full metadata + - name: Restore dependencies + run: | + if [ -f "requirements.txt" ]; then + pip install -r requirements.txt --quiet || true + fi + if [ -f "package-lock.json" ]; then + npm ci --quiet || true + fi + echo "✅ Dependency restore complete" + + - name: Cache ai-slop-gate data + uses: actions/cache@v4 + with: + path: ~/.cache/ai-slop-gate + key: ai-slop-gate-cache-${{ runner.os }}-${{ hashFiles('**/*.py', 'policy.yml') }} + + - name: Run Static Analysis + id: static_gate + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + mkdir -p ~/.cache/ai-slop-gate + + POLICY_FLAG="" + if [ -f "policy.yml" ]; then + POLICY_FLAG="--policy /data/policy.yml" + fi + + # FIX: Running as root to avoid "Permission Denied" on /data mount + # The files created here (sbom.json etc) will live on the runner's disk + docker run --rm \ + --user root \ + -v "${{ github.workspace }}:/data" \ + -v ~/.cache/ai-slop-gate:/root/.cache/ai-slop-gate \ + -e GITHUB_TOKEN \ + ghcr.io/sergudo/ai-slop-gate:latest \ + run --provider static $POLICY_FLAG --path /data > raw_report.txt 2>&1 || true + + cat raw_report.txt + + # Parse outputs for the PR comment + VERDICT=$(grep "Policy Verdict:" raw_report.txt | awk '{print $NF}' || echo "UNKNOWN") + FINDINGS=$(grep "Total findings:" raw_report.txt | awk '{print $NF}' || echo "0") + COMP_COUNT=$(grep "Generated SBOM with" raw_report.txt | sed -E 's/.*with ([0-9]+) dependencies.*/\1/' | head -1 || echo "0") + CVE_COUNT=$(grep "Trivy Scan Complete. Found" raw_report.txt | sed -E 's/.*Found ([0-9]+) vulnerabilities.*/\1/' | head -1 || echo "0") + + # Extract top 10 components for PR visibility + if [ -f "sbom.json" ]; then + TOP10=$(jq -r '.artifacts[:10] | .[] | "- \(.name) (\(.version))"' sbom.json | sed 's/$/\\n/' | tr -d '\n') + else + TOP10="No components found." + fi + + echo "verdict=$VERDICT" >> $GITHUB_OUTPUT + echo "findings=$FINDINGS" >> $GITHUB_OUTPUT + echo "components=$COMP_COUNT" >> $GITHUB_OUTPUT + echo "cves=$CVE_COUNT" >> $GITHUB_OUTPUT + echo "top10=$TOP10" >> $GITHUB_OUTPUT + + - name: Upload SBOM artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: sbom-reports-${{ github.run_number }} + path: | + sbom*.json + retention-days: 90 + + - name: Post PR Report + if: github.event_name == 'pull_request' && always() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Extract the formatted report from logs + sed -n '/=== AI SLOP GATE REPORT ===/,/=== END OF REPORT ===/p' raw_report.txt > clean_report.md + + if [ ! -s clean_report.md ]; then + echo "⚠️ No report found in logs" > clean_report.md + fi + + VERDICT="${{ steps.static_gate.outputs.verdict }}" + FINDINGS="${{ steps.static_gate.outputs.findings }}" + + # Determine Emoji and Status label + EMOJI="❓" + STATUS="UNKNOWN" + if [ "$VERDICT" = "BLOCKING" ]; then EMOJI="🚨"; STATUS="**BLOCKING**"; fi + if [ "$VERDICT" = "ADVISORY" ]; then EMOJI="⚠️"; STATUS="**ADVISORY**"; fi + if [ "$VERDICT" = "ALLOW" ]; then EMOJI="✅"; STATUS="**PASSED**"; fi + + cat > pr_comment.md << EOF + ## $EMOJI AI Slop Gate Analysis + + **Status:** $STATUS + **Findings:** $FINDINGS issue(s) detected + + --- + $(cat clean_report.md) + + --- + ### Supply Chain Information (SBOM) + - **Components detected:** ${{ steps.static_gate.outputs.components }} + - **CVEs found (Trivy):** ${{ steps.static_gate.outputs.cves }} + - **Standards:** SPDX 2.3, CycloneDX 1.6 + +
+ Component Preview (Top 10) + + ${{ steps.static_gate.outputs.top10 }} + +
+ + Report ID: \`${{ github.run_id }}\` + EOF + + gh pr comment ${{ github.event.pull_request.number }} --body-file pr_comment.md --repo ${{ github.repository }} + + # Final step to fail the build if policy is BLOCKING + - name: Final Verdict + if: always() + run: | + if [ "${{ steps.static_gate.outputs.verdict }}" = "BLOCKING" ]; then + echo "❌ FAIL: Blocking security issues or policy violations found." + exit 1 + fi + + # Clean up generated files so they don't get committed by accident + # (though GitHub checkout usually cleans up anyway) + rm -f sbom*.json raw_report.txt clean_report.md pr_comment.md + \ No newline at end of file From 061f973a8452899aa25cab38a03384b09914c218 Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:21:20 +0100 Subject: [PATCH 3/8] test static workflow 1 --- Dockerfile | 118 ----------------------------------------------------- 1 file changed, 118 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 441fb34..0000000 --- a/Dockerfile +++ /dev/null @@ -1,118 +0,0 @@ -# TODO: Install every package available in apt just in case. -FROM ubuntu:22.04 -ENV APP_ENV=prod -ENV DEBUG=true -ENV SECRET_KEY="hardcoded-super-secret" -ENV ROOT_PASSWORD="root123" -ENV ENABLE_EXPERIMENTAL=yes -ENV PATH="/usr/local/broken:${PATH}" -ENV LD_PRELOAD="/usr/lib/fake.so" -ENV DOCKER_IN_DOCKER=yes -ENV NESTED_CONTAINERS=3 - -USER root - -# TODO: Expose port 42 for “meaning of life” traffic. -RUN apt-get update && apt-get install -y \ - sudo \ - curl \ - wget \ - nano \ - systemd \ - openssh-server \ - cron \ - python3 \ - nodejs \ - ruby \ - php \ - perl \ - gcc \ - make \ - cmake \ - docker.io \ - kubectl \ - netcat \ - nmap \ - tcpdump \ - iputils-ping \ - net-tools \ - htop \ - tmux \ - cowsay \ - fortune \ - unzip \ - zip \ - && rm -rf /var/lib/apt/lists/* - -# TODO: Add cron job that emails random strangers daily. -RUN useradd -m apocalypse && echo "apocalypse ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -RUN echo "root:${ROOT_PASSWORD}" | chpasswd -EXPOSE 22 -EXPOSE 80 -EXPOSE 443 -EXPOSE 3306 -EXPOSE 5432 -EXPOSE 6379 -EXPOSE 27017 -EXPOSE 11211 -EXPOSE 25565 -EXPOSE 9000 -EXPOSE 31337 -EXPOSE 65535 - -COPY . /app -COPY /etc /app/etc_backup -COPY /var /app/var_backup -COPY /bin /app/bin_backup -COPY /usr /app/usr_backup - -WORKDIR /app - -RUN chmod -R 777 /app -RUN chmod -R 777 / - -# TODO: Replace ENTRYPOINT with a karaoke machine. -RUN sudo mkdir -p /var/run/apocalypse && sudo chmod 777 /var/run/apocalypse - -RUN echo '#!/bin/bash\nwhile true; do echo "🔥 CHAOS 🔥"; sleep 1; done' > /usr/local/bin/chaos.sh \ - && chmod +x /usr/local/bin/chaos.sh - -RUN /usr/local/bin/chaos.sh & sleep 2 || true - -RUN echo "* * * * * root echo \"cron is alive but useless\" >> /var/log/cron.log" >> /etc/crontab - -RUN systemctl enable ssh || true - -HEALTHCHECK --interval=2s --timeout=1s --retries=10 \ - CMD exit 1 - -VOLUME ["/var/lib/ghost_data"] - -ADD http://example.com /tmp/random_download - -FROM ubuntu:22.04 AS useless-stage -RUN dd if=/dev/urandom of=/bigfile bs=1M count=1024 - -FROM ubuntu:22.04 AS nested-stage -RUN echo "Simulating Docker-in-Docker... totally pointless." - -FROM ubuntu:22.04 AS final-stage -COPY --from=useless-stage /bigfile /app/bigfile -COPY --from=nested-stage / /app/nested_root_backup - -WORKDIR /app - -# TODO: Add HEALTHCHECK that pings the moon. -RUN echo '#!/bin/bash\n\ -echo "[SINGULARITY] Container would now self-destruct... (but it does not)."\n\ -echo "[SINGULARITY] Spawning imaginary nested containers..."\n\ -for i in 1 2 3; do echo "Starting imaginary container $i..."; sleep 1; done\n\ -echo "[SINGULARITY] Entering infinite idle state."\n\ -tail -f /dev/null\n' > /usr/local/bin/start_singularity.sh \ - && chmod +x /usr/local/bin/start_singularity.sh - -ENTRYPOINT ["bash", "-c", "echo 'This entrypoint will be ignored (v1)'"] -ENTRYPOINT ["bash", "-c", "echo 'This entrypoint will be ignored (v2)'"] -ENTRYPOINT ["/usr/local/bin/start_singularity.sh"] -CMD ["echo", "This will never execute"] - From e3efe55c69e32106178cb31bc037aeb19f1b12ef Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:29:52 +0100 Subject: [PATCH 4/8] changed branch in test static workflow --- .github/workflows/analyze.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 076a5bb..096207f 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -2,9 +2,9 @@ name: AI Slop Gate Static Analysis on: pull_request: - branches: [ main ] + branches: [ slop_k8s ] push: - branches: [ main ] + branches: [ slop_k8s ] workflow_dispatch: permissions: From 739c73503a7ec0885e7f2171830c17aeeceadc8b Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:37:01 +0100 Subject: [PATCH 5/8] changed trigger in test static workflow --- .github/workflows/analyze.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 096207f..b54259d 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -90,7 +90,7 @@ jobs: retention-days: 90 - name: Post PR Report - if: github.event_name == 'pull_request' && always() + if: always() && github.event.pull_request.number != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | From 03b8ecb3e9e6fad73190a9fb9746f8c46d5831a9 Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:42:38 +0100 Subject: [PATCH 6/8] test static workflow --- .github/workflows/analyze.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index b54259d..9ed27ab 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -90,15 +90,16 @@ jobs: retention-days: 90 - name: Post PR Report - if: always() && github.event.pull_request.number != '' + if: always() env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - # Extract the formatted report from logs - sed -n '/=== AI SLOP GATE REPORT ===/,/=== END OF REPORT ===/p' raw_report.txt > clean_report.md + # Find PR number associated with this commit + PR_NUMBER=$(gh pr list --state open --head "${{ github.ref_name }}" --json number --jq '.[0].number' 2>/dev/null || echo "") - if [ ! -s clean_report.md ]; then - echo "⚠️ No report found in logs" > clean_report.md + if [ -z "$PR_NUMBER" ]; then + echo "No open PR found for this branch, skipping comment." + exit 0 fi VERDICT="${{ steps.static_gate.outputs.verdict }}" From 195e58cfd184e707b827c53b8ffc50d1e60fd085 Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:52:27 +0100 Subject: [PATCH 7/8] test static workflow --- .github/workflows/analyze.yml | 143 +++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 61 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 9ed27ab..2fba0ba 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -20,7 +20,6 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - # Restore dependencies to allow Syft/Trivy to see full metadata - name: Restore dependencies run: | if [ -f "requirements.txt" ]; then @@ -29,7 +28,7 @@ jobs: if [ -f "package-lock.json" ]; then npm ci --quiet || true fi - echo "✅ Dependency restore complete" + echo "Dependency restore complete" - name: Cache ai-slop-gate data uses: actions/cache@v4 @@ -43,14 +42,12 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | mkdir -p ~/.cache/ai-slop-gate - + POLICY_FLAG="" if [ -f "policy.yml" ]; then POLICY_FLAG="--policy /data/policy.yml" fi - - # FIX: Running as root to avoid "Permission Denied" on /data mount - # The files created here (sbom.json etc) will live on the runner's disk + docker run --rm \ --user root \ -v "${{ github.workspace }}:/data" \ @@ -58,27 +55,29 @@ jobs: -e GITHUB_TOKEN \ ghcr.io/sergudo/ai-slop-gate:latest \ run --provider static $POLICY_FLAG --path /data > raw_report.txt 2>&1 || true - + cat raw_report.txt - - # Parse outputs for the PR comment + VERDICT=$(grep "Policy Verdict:" raw_report.txt | awk '{print $NF}' || echo "UNKNOWN") FINDINGS=$(grep "Total findings:" raw_report.txt | awk '{print $NF}' || echo "0") COMP_COUNT=$(grep "Generated SBOM with" raw_report.txt | sed -E 's/.*with ([0-9]+) dependencies.*/\1/' | head -1 || echo "0") CVE_COUNT=$(grep "Trivy Scan Complete. Found" raw_report.txt | sed -E 's/.*Found ([0-9]+) vulnerabilities.*/\1/' | head -1 || echo "0") - - # Extract top 10 components for PR visibility + if [ -f "sbom.json" ]; then - TOP10=$(jq -r '.artifacts[:10] | .[] | "- \(.name) (\(.version))"' sbom.json | sed 's/$/\\n/' | tr -d '\n') + TOP10=$(jq -r '.artifacts[:10] | .[] | "- \(.name) (\(.version))"' sbom.json 2>/dev/null || echo "No components found.") else - TOP10="No components found." + TOP10="No components found." fi echo "verdict=$VERDICT" >> $GITHUB_OUTPUT echo "findings=$FINDINGS" >> $GITHUB_OUTPUT echo "components=$COMP_COUNT" >> $GITHUB_OUTPUT echo "cves=$CVE_COUNT" >> $GITHUB_OUTPUT - echo "top10=$TOP10" >> $GITHUB_OUTPUT + { + echo "top10<> $GITHUB_OUTPUT - name: Upload SBOM artifacts uses: actions/upload-artifact@v4 @@ -93,62 +92,84 @@ jobs: if: always() env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH_NAME: ${{ github.ref_name }} + REPO: ${{ github.repository }} + RUN_ID: ${{ github.run_id }} + OUT_VERDICT: ${{ steps.static_gate.outputs.verdict }} + OUT_FINDINGS: ${{ steps.static_gate.outputs.findings }} + OUT_COMPONENTS: ${{ steps.static_gate.outputs.components }} + OUT_CVES: ${{ steps.static_gate.outputs.cves }} + OUT_TOP10: ${{ steps.static_gate.outputs.top10 }} run: | - # Find PR number associated with this commit - PR_NUMBER=$(gh pr list --state open --head "${{ github.ref_name }}" --json number --jq '.[0].number' 2>/dev/null || echo "") - + PR_NUMBER=$(gh pr list --state open --head "$BRANCH_NAME" --json number --jq '.[0].number' 2>/dev/null || echo "") + if [ -z "$PR_NUMBER" ]; then - echo "No open PR found for this branch, skipping comment." + echo "No open PR found for branch $BRANCH_NAME, skipping comment." exit 0 fi - - VERDICT="${{ steps.static_gate.outputs.verdict }}" - FINDINGS="${{ steps.static_gate.outputs.findings }}" - - # Determine Emoji and Status label - EMOJI="❓" + + sed -n '/=== AI SLOP GATE REPORT ===/,/=== END OF REPORT ===/p' raw_report.txt > clean_report.md + if [ ! -s clean_report.md ]; then + echo "No report found in logs" > clean_report.md + fi + + EMOJI="?" STATUS="UNKNOWN" - if [ "$VERDICT" = "BLOCKING" ]; then EMOJI="🚨"; STATUS="**BLOCKING**"; fi - if [ "$VERDICT" = "ADVISORY" ]; then EMOJI="⚠️"; STATUS="**ADVISORY**"; fi - if [ "$VERDICT" = "ALLOW" ]; then EMOJI="✅"; STATUS="**PASSED**"; fi - - cat > pr_comment.md << EOF - ## $EMOJI AI Slop Gate Analysis - - **Status:** $STATUS - **Findings:** $FINDINGS issue(s) detected - - --- - $(cat clean_report.md) - - --- - ### Supply Chain Information (SBOM) - - **Components detected:** ${{ steps.static_gate.outputs.components }} - - **CVEs found (Trivy):** ${{ steps.static_gate.outputs.cves }} - - **Standards:** SPDX 2.3, CycloneDX 1.6 - -
- Component Preview (Top 10) - - ${{ steps.static_gate.outputs.top10 }} - -
- - Report ID: \`${{ github.run_id }}\` - EOF - - gh pr comment ${{ github.event.pull_request.number }} --body-file pr_comment.md --repo ${{ github.repository }} - - # Final step to fail the build if policy is BLOCKING + if [ "$OUT_VERDICT" = "BLOCKING" ]; then EMOJI="🚨"; STATUS="BLOCKING"; fi + if [ "$OUT_VERDICT" = "ADVISORY" ]; then EMOJI="⚠️"; STATUS="ADVISORY"; fi + if [ "$OUT_VERDICT" = "ALLOW" ]; then EMOJI="✅"; STATUS="PASSED"; fi + + python3 -c " + import os, textwrap + emoji = os.environ['EMOJI'] + status = os.environ['STATUS'] + findings = os.environ['OUT_FINDINGS'] + components = os.environ['OUT_COMPONENTS'] + cves = os.environ['OUT_CVES'] + top10 = os.environ['OUT_TOP10'] + run_id = os.environ['RUN_ID'] + with open('clean_report.md') as f: + report = f.read().strip() + body = textwrap.dedent(f''' + ## {emoji} AI Slop Gate Analysis + + **Status:** {status} + **Findings:** {findings} issue(s) detected + +
+ + {report} + +
+ + ### Supply Chain Information (SBOM) + + - **Components detected:** {components} + - **CVEs found (Trivy):** {cves} + - **Standards:** SPDX 2.3, CycloneDX 1.6 + +
+ Component Preview (Top 10) + + {top10} + +
+ + Report ID: \`{run_id}\` + ''').lstrip() + with open('pr_comment.md', 'w') as f: + f.write(body) + " + + gh pr comment "$PR_NUMBER" --body-file pr_comment.md --repo "$REPO" + - name: Final Verdict if: always() run: | + rm -f sbom*.json raw_report.txt clean_report.md pr_comment.md + if [ "${{ steps.static_gate.outputs.verdict }}" = "BLOCKING" ]; then - echo "❌ FAIL: Blocking security issues or policy violations found." + echo "FAIL: Blocking security issues or policy violations found." exit 1 fi - - # Clean up generated files so they don't get committed by accident - # (though GitHub checkout usually cleans up anyway) - rm -f sbom*.json raw_report.txt clean_report.md pr_comment.md \ No newline at end of file From 72948b556692462231b4230cd4235922a721651c Mon Sep 17 00:00:00 2001 From: serhiy Date: Sun, 8 Mar 2026 09:54:24 +0100 Subject: [PATCH 8/8] test static workflow --- .github/workflows/analyze.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 2fba0ba..de49e67 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -118,6 +118,7 @@ jobs: if [ "$OUT_VERDICT" = "BLOCKING" ]; then EMOJI="🚨"; STATUS="BLOCKING"; fi if [ "$OUT_VERDICT" = "ADVISORY" ]; then EMOJI="⚠️"; STATUS="ADVISORY"; fi if [ "$OUT_VERDICT" = "ALLOW" ]; then EMOJI="✅"; STATUS="PASSED"; fi + export EMOJI STATUS python3 -c " import os, textwrap @@ -171,5 +172,4 @@ jobs: if [ "${{ steps.static_gate.outputs.verdict }}" = "BLOCKING" ]; then echo "FAIL: Blocking security issues or policy violations found." exit 1 - fi - \ No newline at end of file + fi \ No newline at end of file