Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,18 @@ For specific topics, see:
- @agent_docs/architecture.md - Component details, CRD structure, configuration
- @agent_docs/development.md - Building, testing, code generation
- @agent_docs/deployment.md - OLM deployment, container builds

## Contextification Addendum

Low-token routing:

- Entrypoint: `cmd/`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Inconsistent entrypoint directory within the same file.

The low-token routing uses cmd/ but the Project Structure section above specifies cmd/security-labeller/. Use the precise path for consistency.

- - Entrypoint: `cmd/`
+ - Entrypoint: `cmd/security-labeller/`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Entrypoint: `cmd/`
- Entrypoint: `cmd/security-labeller/`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@AGENTS.md` at line 48, The Project Structure section in AGENTS.md is
inconsistent with the entrypoint path used elsewhere, since it refers to the
generic cmd/ directory instead of the specific cmd/security-labeller/
entrypoint. Update the entrypoint reference in that section to match the exact
path already used in the low-token routing guidance so the file consistently
points to the same executable location.

- CRD/API: `apis/secscan/v1alpha1/`
- Reconciliation/labelling: `labeller/`
- Registry security client: `secscan/`
- Image parsing: `image/`
- Generated clients: `generated/` (do not edit)

Commands: `make build`, `make run`, `make installcrds`, `go test -v ./...`, `make codegen`.

Guardrail: pod labels are summaries; full CVE details belong in `ImageManifestVuln`.
127 changes: 127 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# container-security-operator Architecture

## Purpose

Display Clair vulnerability scan results in OpenShift web console.

```mermaid
flowchart LR
quay[Quay and Clair]
vuln[ImageManifestVuln CR]
operator[container-security-operator]
pods[Pods using scanned images]
labels[security labels]
console[OpenShift console]

quay --> vuln
vuln --> operator
pods --> operator
operator --> labels
labels --> pods
pods --> console
```

## High-Level Design

```
Clair/Quay (creates ImageManifestVuln CRs)
container-security-operator (watches CRs + Pods)
↓ Labels pods with vuln info
OpenShift Console (displays security tab)
```

## Components

### `/apis/secscan/v1alpha1`
CRD definitions:
- `ImageManifestVuln`: Vulnerability data for image manifest
- Severity (Critical, High, Medium, Low)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Incomplete severity enumeration in CRD definition.

The ImageManifestVuln severity list omits Defcon1, Negligible, and Unknown which are defined in the actual vulnerability count logic (labeller/manifest.go:23-42). This creates a discrepancy between documentation and code.

-  - Severity (Critical, High, Medium, Low)
+  - Severity (Defcon1, Critical, High, Medium, Low, Negligible, Unknown)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Severity (Critical, High, Medium, Low)
- Severity (Defcon1, Critical, High, Medium, Low, Negligible, Unknown)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ARCHITECTURE.md` at line 39, Update the ImageManifestVuln severity
documentation to match the actual severity handling in the vulnerability count
logic. Expand the severity enumeration in ARCHITECTURE.md to include Defcon1,
Negligible, and Unknown so it aligns with the symbols used in
labeller/manifest.go and no longer conflicts with the implemented severity set.

- CVE details
- Affected packages

### `/cmd/manager`
Operator entrypoint:
- Controller manager
- Watches ImageManifestVuln + Pod resources

### `/labeller`
Pod labeling logic:
- Matches Pods to ImageManifestVuln by image digest
- Adds labels: `secscan/hasVulnerabilities`, `secscan/highestSeverity`
- Updates labels on vuln changes

### `/k8sutils`
Kubernetes client helpers:
- Pod queries
- Label updates
- Event recording

## Data Flow

```
1. Quay/Clair scans image → creates ImageManifestVuln CR:
apiVersion: secscan.quay.redhat.com/v1alpha1
kind: ImageManifestVuln
metadata:
name: sha256-abc123...
spec:
image: quay.io/org/app@sha256:abc123
manifest: sha256:abc123
features:
- name: curl
version: 7.68.0
vulnerabilities:
- name: CVE-2023-1234
severity: High
fixedBy: 7.68.1

2. operator watches ImageManifestVuln creation

3. operator queries Pods using image sha256:abc123

4. operator labels matching Pods:
secscan/hasVulnerabilities: "true"
secscan/highestSeverity: "High"
secscan/affectedByVulns: "CVE-2023-1234,CVE-2023-5678"

Comment on lines +84 to +87

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify affectedByVulns label existence and truncation logic
ast-grep run --pattern 'affectedByVulns' --lang go
rg -n 'affectedByVulns' --type=go

Repository: quay/container-security-operator

Length of output: 170


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== ARCHITECTURE.md around the cited lines ==\n'
sed -n '70,100p' ARCHITECTURE.md || true

printf '\n== Search for secscan label references ==\n'
rg -n 'secscan/|affectedByVulns|hasVulnerabilities|highestSeverity|CVE-2023|truncate|63 characters|label value limit' .

printf '\n== Go files mentioning secscan ==\n'
rg -n 'secscan' --type=go .

Repository: quay/container-security-operator

Length of output: 26996


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== labeller/manifest.go label construction ==\n'
sed -n '70,170p' labeller/manifest.go

printf '\n== label-related helpers in labeller/manifest.go ==\n'
sed -n '1,70p' labeller/manifest.go

printf '\n== occurrences of Label map keys in labeller ==\n'
rg -n 'Labels|labelPrefix|hasVulnerabilities|highestSeverity|affectedByVulns' labeller

Repository: quay/container-security-operator

Length of output: 6316


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== labeller/manifest.go 170-240 ==\n'
sed -n '170,240p' labeller/manifest.go

printf '\n== labeller/labeller.go label interactions ==\n'
sed -n '500,620p' labeller/labeller.go

printf '\n== search for Kubernetes label value length handling ==\n'
rg -n '63|length|truncate|truncat|label.*value|Kubernetes.*label|allowed by the label syntax' .

Repository: quay/container-security-operator

Length of output: 16486


Remove secscan/affectedByVulns from this architecture doc or add the missing label handling.
The operator only writes secscan/hasVulnerabilities and secscan/highestSeverity; affectedByVulns isn’t implemented, and label values aren’t truncated today.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ARCHITECTURE.md` around lines 84 - 87, The architecture doc is describing a
label that the operator does not actually support. Update the docs around the
label handling in the relevant section so they only mention the labels written
by the operator’s current logic, such as secscan/hasVulnerabilities and
secscan/highestSeverity, or add implementation support for
secscan/affectedByVulns if that behavior is intended. Refer to the label-writing
code path and any documentation entries for these labels to keep them
consistent.

5. OpenShift console reads labels → displays in Security tab
```

## Labeling Strategy

Pod labels:
- `secscan/hasVulnerabilities`: "true" | "false"
- `secscan/highestSeverity`: "Critical" | "High" | "Medium" | "Low"
- `secscan/affectedByVulns`: comma-separated CVE list (truncated if >63 chars)

Comment on lines +93 to +97

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Incomplete severity enumeration in label values.

The secscan/highestSeverity label values omit Defcon1, Negligible, and Unknown which the operator can produce per labeller/manifest.go:23-42. This misrepresents the possible label values.

- `secscan/highestSeverity`: "Critical" | "High" | "Medium" | "Low"
+ `secscan/highestSeverity`: "Defcon1" | "Critical" | "High" | "Medium" | "Low" | "Negligible" | "Unknown"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Pod labels:
- `secscan/hasVulnerabilities`: "true" | "false"
- `secscan/highestSeverity`: "Critical" | "High" | "Medium" | "Low"
- `secscan/affectedByVulns`: comma-separated CVE list (truncated if >63 chars)
Pod labels:
- `secscan/hasVulnerabilities`: "true" | "false"
- `secscan/highestSeverity`: "Defcon1" | "Critical" | "High" | "Medium" | "Low" | "Negligible" | "Unknown"
- `secscan/affectedByVulns`: comma-separated CVE list (truncated if >63 chars)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ARCHITECTURE.md` around lines 93 - 97, The Pod label documentation for
secscan/highestSeverity is incomplete and does not match the values produced by
the labeller. Update the label value list in the Pod labels section to include
all possible severities from the labeller/manifest.go logic, specifically
Defcon1, Negligible, and Unknown, alongside the existing Critical, High, Medium,
and Low values.

## Reconciliation

```
Watch ImageManifestVuln:
On create/update:
- Extract image digest
- Find Pods with matching image
- Calculate highest severity
- Apply labels

Watch Pods:
On create:
- Extract image digest
- Find ImageManifestVuln for digest
- Apply labels if vulns exist
```

## Performance

- Indexer for image digest → ImageManifestVuln mapping
- Batch label updates (multiple pods with same image)
- No polling (watch-based)

## OpenShift Integration

Console plugin displays:
- Vulnerability count by severity
- CVE details with links to NVD
- Affected packages + fixed versions
- Drill-down from workload → vulns
42 changes: 42 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Contributing to container-security-operator

## Setup

```bash
# Requires OpenShift cluster with Quay integration
make install
make deploy
```

## Development

Displays Clair vulnerability scan results in OpenShift console.

Watches:
- `ImageManifestVuln` CRs (created by Clair/Quay)
- Pods (to link vulns to running workloads)

## Testing

```bash
# Unit tests
make test

# E2E (requires OpenShift + Quay with Clair)
make test-e2e
```

## Pull Requests

- Test on OpenShift 4.x
- Update labeller logic tests
- Verify console UI displays correctly
- Update CRD if adding new fields

## Code Structure

- `apis/secscan/v1alpha1/` - CRD types
- `cmd/manager/` - operator entrypoint
- `labeller/` - pod vulnerability labeling
- `k8sutils/` - K8s client helpers
- `bundle/` - OLM metadata
Comment on lines +38 to +42

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Directory path inconsistency and incompleteness.

The Code Structure section lists cmd/manager/ but AGENTS.md references cmd/security-labeller/. These must be consistent. Also missing secscan/, image/, generated/, and hack/ directories that are referenced in README.md and AGENTS.md.

  - `apis/secscan/v1alpha1/` - CRD types
- - `cmd/manager/` - operator entrypoint
+ - `cmd/security-labeller/` - operator entrypoint
  - `labeller/` - pod vulnerability labeling
  - `k8sutils/` - K8s client helpers
+ - `secscan/` - registry client for vulnerability data
+ - `image/` - container image ID parsing
+ - `generated/` - auto-generated clients (do not edit)
+ - `hack/` - build scripts and helpers
  - `bundle/` - OLM metadata
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `apis/secscan/v1alpha1/` - CRD types
- `cmd/manager/` - operator entrypoint
- `labeller/` - pod vulnerability labeling
- `k8sutils/` - K8s client helpers
- `bundle/` - OLM metadata
- `apis/secscan/v1alpha1/` - CRD types
- `cmd/security-labeller/` - operator entrypoint
- `labeller/` - pod vulnerability labeling
- `k8sutils/` - K8s client helpers
- `secscan/` - registry client for vulnerability data
- `image/` - container image ID parsing
- `generated/` - auto-generated clients (do not edit)
- `hack/` - build scripts and helpers
- `bundle/` - OLM metadata
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONTRIBUTING.md` around lines 38 - 42, Update the Code Structure section so
it matches the actual project layout and the other docs: replace the
inconsistent operator entrypoint path in the directory list to use the same
symbol/path referenced by AGENTS.md, and add the missing top-level directories
referenced elsewhere, including secscan/, image/, generated/, and hack/. Keep
the directory descriptions aligned with README.md and AGENTS.md so the
documented structure is consistent across the repo.

23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,26 @@ Check if a pod has any vulnerability, and list the CVEs, if any:
```sh
$ kubectl get imagemanifestvulns.secscan.quay.redhat.com --selector=<namespace>/<pod-name> -o jsonpath='{.items[*].spec.features[*].vulnerabilities[*].name}'
```

## Contextification Addendum

```mermaid
flowchart LR
quay[Quay and Clair]
vuln[ImageManifestVuln]
operator[container-security-operator]
pods[Pods]
labels[security labels]
console[OpenShift console]

quay --> vuln
vuln --> operator
pods --> operator
operator --> labels
labels --> pods
pods --> console
```

Key paths: `apis/secscan/v1alpha1/`, `cmd/`, `labeller/`, `secscan/`, `image/`, `generated/`, `bundle/`, and `hack/`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use precise and consistent entrypoint directory name.

cmd/ is ambiguous. CONTRIBUTING.md uses cmd/manager/, AGENTS.md uses cmd/security-labeller/, and ARCHITECTURE.md references /cmd/manager. Standardize on the actual directory name.

- Key paths: `apis/secscan/v1alpha1/`, `cmd/`, `labeller/`, `secscan/`, `image/`, `generated/`, `bundle/`, and `hack/`.
+ Key paths: `apis/secscan/v1alpha1/`, `cmd/security-labeller/`, `labeller/`, `secscan/`, `image/`, `generated/`, `bundle/`, and `hack/`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Key paths: `apis/secscan/v1alpha1/`, `cmd/`, `labeller/`, `secscan/`, `image/`, `generated/`, `bundle/`, and `hack/`.
Key paths: `apis/secscan/v1alpha1/`, `cmd/security-labeller/`, `labeller/`, `secscan/`, `image/`, `generated/`, `bundle/`, and `hack/`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 153, The README “Key paths” entry uses the ambiguous cmd/
label, so update that list to the repo’s actual entrypoint directory name and
make it consistent with the references in CONTRIBUTING.md, AGENTS.md, and
ARCHITECTURE.md. Locate the README key-paths section and replace every
entrypoint mention with the same canonical directory name used by the codebase
so all docs point to one standard path.


Use `make build`, `make run`, `make installcrds`, `go test -v ./...`, and `make codegen`. Do not edit generated clients manually.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Makefile test target
cat Makefile | grep -A3 '^test:'

Repository: quay/container-security-operator

Length of output: 170


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'FILES:\n'
git ls-files | rg '(^|/)(Makefile|README\.md|CONTRIBUTING\.md)$' || true

printf '\nMAKEFILE TEST TARGET SEARCH:\n'
rg -n '^[[:space:]]*test:' Makefile || true

printf '\nMAKEFILE TEST REFERENCES:\n'
rg -n 'make test|go test -v ./\.\.\.|go test' Makefile README.md CONTRIBUTING.md || true

printf '\nCONTRIBUTING EXCERPT:\n'
if [ -f CONTRIBUTING.md ]; then
  rg -n -A3 -B3 'make test|go test -v ./\.\.\.' CONTRIBUTING.md || true
fi

printf '\nREADME EXCERPT:\n'
if [ -f README.md ]; then
  rg -n -A3 -B3 'make build|make run|make installcrds|go test -v ./\.\.\.|make codegen' README.md || true
fi

Repository: quay/container-security-operator

Length of output: 1229


🏁 Script executed:

#!/bin/bash
set -euo pipefail

wc -l Makefile CONTRIBUTING.md README.md

printf '\nMAKEFILE TARGETS:\n'
rg -n '^[A-Za-z0-9_.-]+:' Makefile

printf '\nMAKEFILE TEST-RELATED LINES:\n'
rg -n 'go test|test-e2e|unit test|unit tests|test:' Makefile

printf '\nCONTRIBUTING TEST-RELATED LINES:\n'
rg -n -A2 -B2 'make test|go test|unit test|unit tests' CONTRIBUTING.md

printf '\nREADME TEST-RELATED LINES:\n'
rg -n -A2 -B2 'make test|go test|unit test|unit tests' README.md

Repository: quay/container-security-operator

Length of output: 556


Standardize the test command in the docs

CONTRIBUTING.md still references make test, but this Makefile doesn’t define a test target. Align the contributor docs with the actual command (go test -v ./...) or add the missing target.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 155, The contributor docs still mention a non-existent
make test target, so update the docs to match the real test command or add the
missing target. Adjust the relevant documentation entry that references
build/run/test commands, and ensure it consistently points to go test -v ./...
rather than make test so contributors use the supported workflow.

Loading