Skip to content

profile-compaction: CollapseConfig CRD + projection overlay + signing/tamper detection#847

Open
matthyx wants to merge 1 commit into
mainfrom
profile-compaction-808
Open

profile-compaction: CollapseConfig CRD + projection overlay + signing/tamper detection#847
matthyx wants to merge 1 commit into
mainfrom
profile-compaction-808

Conversation

@matthyx

@matthyx matthyx commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Same-repo mirror of #808 (which is from the k8sstormcenter fork) so the gated Node Agent Component Tests and build-and-push-image (pull_request) workflows run with repo secrets.

Single squashed commit, rebased on main, conflicts resolved.

Overview

Adds cryptographic profile signing & tamper detection plus the CollapseConfig projection-overlay / user-managed lifecycle work:

  • pkg/signature (cosign-backed sign/verify; key-based + keyless) + per-kind adapters (AP / NN / seccomp / rules)
  • Tamper detection that re-verifies signed user overlays on cache load and emits R1016 "Signed profile tampered"
  • Rule-signature verification in ruleswatcher
  • sign-object CLI (sign / verify / generate-keypair / extract-signature)
  • User-defined NetworkNeighborhood overlay + SyncChecksum overlay-identity stamping
  • enableSignatureVerification config flag

Conflict resolution

This PR predates the merged #806 (network wildcards) and #807 (exec-args) and independently reimplemented the projection surface. Per maintainer decision, main's tested design was kept (projectField(isPathSurface), ExecsByPath [][]string, rule-binding notificationQueue); the PR's redundant reimplementation was dropped and only its net-new features grafted on top.

Storage dependency

Backed by kubescape/storage #325. go.mod pins the official kubescape/storage v0.0.291 (drops the k8sstormcenter/storage fork replace) and adds sigstore (fulcio, rekor) deps.

Verification (local)

go build ./... ✓ · go vet ./... ✓ · unit tests green for pkg/signature/..., containerprofilecache (incl. test32_projection_test, tamper_alert_test), rulebindingmanager/cache, ruleswatcher, and networkneighborhood (confirms #806 intact).

Note: component tests pull the storage image tag from helm-charts values.yaml; they need that tag at ≥ v0.0.291 to exercise the signed-profile paths.

Mirrors #808.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added profile signing and verification support, including a new CLI for signing, verifying, and extracting signatures.
    • User-managed profiles can now be signed and checked for tampering, with alerts for modified signed profiles.
    • Added support for signed rule syncing and optional signature verification in runtime detection.
  • Bug Fixes

    • Improved handling of signed overlays so tampered profiles are rejected or flagged consistently.
    • Enhanced cache invalidation when user overlays change or are removed.
  • Documentation

    • Added release notes for the new signing and tamper-detection behavior.

@matthyx matthyx added the ai-assisted Created through Armosec AI tooling (armosec-shared-rules plugin) label Jun 26, 2026
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a profile-signing library and CLI, runtime rule and container-profile signature verification, R1016 tamper alert emission for signed overlays, and expanded component tests, fixtures, docs, and workflow entries.

Changes

Profile signing and tamper detection

Layer / File(s) Summary
Signature contracts and profile adapters
pkg/signature/interface.go, pkg/signature/annotations.go, pkg/signature/profiles/applicationprofile_adapter.go, pkg/signature/profiles/networkneighborhood_adapter.go, pkg/signature/profiles/seccompprofile_adapter.go, pkg/signature/profiles/rules_adapter.go
Defines shared signing interfaces, annotation keys, and adapters for ApplicationProfile, NetworkNeighborhood, SeccompProfile, and Rules.
Adapter behavior tests
pkg/signature/profiles/*_test.go
Verifies adapter content mapping, annotation handling, empty TypeMeta fallbacks, and adapter-level sign/verify round trips across the profile adapters.
Cosign adapter and signature primitives
go.mod, pkg/signature/cosign_adapter.go, pkg/signature/signer.go, pkg/signature/verifier.go, pkg/signature/cosign_adapter_test.go, pkg/signature/cluster_flow_test.go
Adds the cosign-backed signer/verifier, content hashing, annotation encoding/decoding, dependency updates, and low-level signing tests.
Object sign and verify APIs
pkg/signature/sign.go, pkg/signature/verify.go, pkg/signature/sign_test.go, pkg/signature/verify_test.go, pkg/signature/cluster_scenario_test.go
Adds object-level signing and verification helpers plus tests for local and keyless signing, tamper detection, and signature/log inspection.
sign-object CLI
cmd/sign-object/main.go, cmd/sign-object/Dockerfile
Adds the sign-object command-line tool, object-type detection, and a multi-stage image for the new tool.
Rule manager verification
pkg/rulemanager/cel/libraries/applicationprofile/ap.go, pkg/rulemanager/cel/libraries/cache/function_cache.go, pkg/config/config.go, cmd/main.go, pkg/rulemanager/ruleswatcher/watcher.go, pkg/rulemanager/ruleswatcher/watcher_signature_test.go
Updates rulemanager helper behavior, adds signature verification gating to rule syncing, and threads the config into watcher startup and tests.
Container profile tamper detection
pkg/objectcache/shared_container_data.go, pkg/containerprofilemanager/v1/lifecycle.go, pkg/objectcache/containerprofilecache/containerprofilecache.go, pkg/objectcache/containerprofilecache/projection.go, pkg/objectcache/containerprofilecache/tamper_alert.go, pkg/exporters/alert_manager.go, cmd/main.go, tests/chart/templates/node-agent/default-rules.yaml, pkg/objectcache/containerprofilecache/tamper_alert_test.go, pkg/objectcache/containerprofilecache/test32_projection_test.go
Adds user-defined network metadata propagation, checksum stamping for overlays, repeated overlay signature verification, R1016 alert emission, and cache/projection tests.
Component validation and fixtures
.github/workflows/component-tests.yaml, tests/component_test.go, docs/features/profile-signing-and-tamper-detection.md, tests/resources/aplint_test.go, tests/resources/curl-signed-deployment.yaml, tests/resources/known-application-profile.yaml
Adds component tests, workflow entries, fixture linting, documentation, and YAML fixtures for signed profiles.

Sequence Diagram(s)

sequenceDiagram
  participant ContainerProfileCacheImpl
  participant verifyUserApplicationProfile
  participant signature
  participant emitTamperAlert
  participant "exporters.Exporter" as Exporter

  ContainerProfileCacheImpl->>verifyUserApplicationProfile: load signed overlay
  verifyUserApplicationProfile->>signature: VerifyObjectAllowUntrusted(...)
  signature-->>verifyUserApplicationProfile: ErrSignatureMismatch
  verifyUserApplicationProfile->>emitTamperAlert: build R1016 alert
  emitTamperAlert->>Exporter: SendRuleAlert(...)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

  • kubescape/node-agent#788: Shares the pkg/objectcache/containerprofilecache path that this PR extends with signature re-verification, overlay stamping, and tamper alerts.
  • kubescape/node-agent#799: Touches the SyncChecksum and projection path that this PR updates for overlay identity stamping and cache invalidation.

Poem

I hopped on checksums, soft and bright,
And signed the profiles late at night.
When tamper nibbled at the leaf,
R1016 rang to catch the thief.
Then safe hare paths went hoppity-zip.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and matches the main themes of the PR: projection overlay changes plus signing and tamper detection.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch profile-compaction-808

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@matthyx matthyx force-pushed the profile-compaction-808 branch from 432fef2 to e643967 Compare June 26, 2026 20:53
@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.186 0.000 -100.0%
Peak CPU (cores) 0.193 0.000 -100.0%
Avg Memory (MiB) 335.216 0.000 -100.0%
Peak Memory (MiB) 342.418 0.000 -100.0%
Dedup Effectiveness

No data available.

@matthyx matthyx force-pushed the profile-compaction-808 branch 2 times, most recently from a460877 to eb14aa8 Compare June 26, 2026 21:19
@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.200 0.000 -100.0%
Peak CPU (cores) 0.213 0.000 -100.0%
Avg Memory (MiB) 320.998 0.000 -100.0%
Peak Memory (MiB) 323.766 0.000 -100.0%
Dedup Effectiveness

No data available.

@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.224 0.216 -3.4%
Peak CPU (cores) 0.234 0.234 -0.2%
Avg Memory (MiB) 338.098 274.291 -18.9%
Peak Memory (MiB) 340.332 280.523 -17.6%
Dedup Effectiveness

No data available.

…naged lifecycle + signing/tamper detection

Squashed and rebased onto main (resolving conflicts against the merged
#806 network-wildcards and #807 exec-args work).

Adds, on top of main's projection surface:
  - Cryptographic signing/verification of ApplicationProfile,
    NetworkNeighborhood, seccomp and rules profiles (pkg/signature,
    cosign-backed, key-based + keyless).
  - Tamper detection for signed user overlays: re-verifies on every
    ContainerProfileCache load and emits R1016 "Signed profile tampered".
  - Rule-signature verification in ruleswatcher.
  - sign-object CLI (sign / verify / generate-keypair / extract-signature).
  - User-defined NetworkNeighborhood overlay support + SyncChecksum
    overlay-identity stamping.
  - enableSignatureVerification config flag.

Conflict resolution: kept main's tested projection design (projectField
isPathSurface, ExecsByPath [][]string) and rule-binding notificationQueue;
the PR's redundant reimplementation of that surface was dropped in favour
of the merged #806/#807 versions. Only the net-new features above were
grafted on top.

go.mod: pins the official kubescape/storage v0.0.291 (carries storage #325),
dropping the temporary k8sstormcenter/storage fork replace; adds sigstore
(fulcio, rekor) dependencies for signing.

Feature documented in docs/features/profile-signing-and-tamper-detection.md.

Syncs R1016 "Signed profile tampered" into the bundled default-rules.yaml
from kubescape/rulelibrary (metadata-only entry, empty ruleExpression since
R1016 is code-emitted, not CEL-evaluated).

Squashed from PR #808 (kubescape/node-agent).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Duck <70207455+entlein@users.noreply.github.com>
@matthyx matthyx force-pushed the profile-compaction-808 branch from eb14aa8 to ea2d117 Compare June 27, 2026 09:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (7)
cmd/sign-object/Dockerfile (1)

17-20: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Run the container as a non-root user.

The final image runs as root. gcr.io/distroless/static-debian13 provides a nonroot user (UID 65532); switching to it reduces blast radius for a tool that handles private keys.

🔒️ Proposed hardening
 FROM gcr.io/distroless/static-debian13:latest
 COPY --from=builder /sign-object /usr/local/bin/sign-object
 WORKDIR /work
+USER nonroot:nonroot
 ENTRYPOINT ["sign-object"]

Note: ensure any mounted /work volume is writable by UID 65532 (relevant for generate-keypair/sign output).

🤖 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 `@cmd/sign-object/Dockerfile` around lines 17 - 20, The final stage of the
sign-object image still runs as root; update the Dockerfile’s distroless runtime
setup to use the built-in nonroot user from gcr.io/distroless/static-debian13
before the ENTRYPOINT. Make the change in the final image configuration so the
container executes as UID 65532, and ensure the /work directory usage remains
compatible with that user for generate-keypair/sign outputs.

Source: Linters/SAST tools

pkg/signature/sign_test.go (1)

194-208: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Positive-path GetObjectSignature subtest is skipped by default.

The "Complete signature" case relies on SignObjectKeyless, gated on ENABLE_KEYLESS_TESTS, so the success path never runs in CI. SignObjectDisableKeyless (used throughout the rest of this PR) signs without any external dependency and would let this subtest exercise the non-error branch by default.

🤖 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 `@pkg/signature/sign_test.go` around lines 194 - 208, The "Complete signature"
test path in sign_test.go is being skipped by default because it calls
SignObjectKeyless behind the ENABLE_KEYLESS_TESTS gate, so the positive
GetObjectSignature branch never runs in CI. Update the setupSign path in the
test table/t.Run logic to use SignObjectDisableKeyless instead of
SignObjectKeyless for this subtest, keeping the env-gated skip only for cases
that truly require keyless signing. This should make the success-case coverage
run by default while preserving the existing test structure around
GetObjectSignature and the tt.setupSign flow.
pkg/rulemanager/ruleswatcher/watcher.go (1)

90-108: 🩺 Stability & Availability | 🔵 Trivial

Enabling verification with unsigned rule resources silently drops all their enabled rules.

When EnableSignatureVerification=true, any unsigned rules resource (including the bundled default rules if unsigned) is rejected by verifyRules, and every enabled rule it carries is skipped — leaving detection with potentially zero active rules. The unsigned case is only logged at Debug inside verifyRules; the sole surfaced signal is the skippedByVerification Info count. Consider documenting this fail-toward-empty behavior and/or emitting a Warning/metric when verification is enabled but a large fraction of rules are skipped, so operators don't unknowingly disable detection.

🤖 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 `@pkg/rulemanager/ruleswatcher/watcher.go` around lines 90 - 108, The rules
sync path in watcher.go is failing closed on unsigned resources, which can
silently remove all enabled rules when EnableSignatureVerification is on. Update
the RulesWatcher flow around unstructuredToRules and verifyRules to make this
behavior explicit: document that unsigned resources are rejected, and add a
higher-signal Warning or metric in the skippedVerificationCount path when many
or all enabled rules are skipped. Keep the existing verifyRules and
skippedByVerification accounting, but ensure operators get visible feedback when
rule coverage drops to near zero.
tests/component_test.go (1)

3370-3398: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated doc comment block for Test_30_TamperedSignedProfiles.

The function-level comment (Lines 3370-3383) is repeated verbatim immediately below (Lines 3385-3398) — likely a rebase artifact. Only the block directly preceding the func is the godoc comment; remove the earlier duplicate.

🤖 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 `@tests/component_test.go` around lines 3370 - 3398, Remove the duplicated doc
comment for Test_30_TamperedSignedProfiles and keep only the single godoc block
immediately preceding the test function. Clean up the repeated comment text in
the component_test.go test section so the Test_30_TamperedSignedProfiles
declaration has just one unique documentation block attached to it.
pkg/objectcache/containerprofilecache/tamper_alert_test.go (1)

350-351: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the stale trailing comment. The comment describes a cfgRef config shim, but no such type exists in the file — the strict-mode tests construct config.Config directly (lines 312, 342). This dangling comment is misleading leftover.

♻️ Proposed cleanup
-
-// cfgRef is a minimal config shim for the strict-mode tests. Mirrors the
-// concrete config.Config struct shape only in the field the verifier reads.
🤖 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 `@pkg/objectcache/containerprofilecache/tamper_alert_test.go` around lines 350
- 351, Remove the stale trailing comment in tamper_alert_test.go that refers to
a cfgRef config shim, since the strict-mode tests use config.Config directly and
no cfgRef type exists. Locate the leftover comment near the strict-mode test
setup around the existing config.Config usage, and delete only that misleading
note without changing the test logic.
pkg/signature/cosign_adapter.go (2)

232-234: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove dead simulateKeyless. It is unused and only returns a deprecation error.

♻️ Proposed removal
-func (c *CosignAdapter) simulateKeyless(data []byte) (*Signature, error) {
-	return nil, fmt.Errorf("simulateKeyless is deprecated, use real keyless signing")
-}
-
🤖 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 `@pkg/signature/cosign_adapter.go` around lines 232 - 234, The simulateKeyless
method on CosignAdapter is dead code and should be removed entirely rather than
kept as a deprecation stub. Delete the unused simulateKeyless function from
cosign_adapter.go, and make sure no remaining references in CosignAdapter or
related signature flow still depend on it; if any callers exist, update them to
use the real keyless signing path instead.

Source: Linters/SAST tools


37-45: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Blank var _ = references mask unused imports. Several of these (cosign.Signature, bundle.RekorBundle, client.Rekor, models.LogEntry) exist only to keep the rekor/cosign imports compiling while their real usage is commented-out placeholder code. Once the Rekor flow is implemented (or dropped), remove these blanks and the corresponding imports to keep the dependency surface honest.

🤖 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 `@pkg/signature/cosign_adapter.go` around lines 37 - 45, The blank var _
references in cosign_adapter.go are only keeping placeholder Rekor/Cosign
imports alive and should be removed once real usage is added or the flow is
dropped. Update the cosign_adapter package by cleaning out the unused symbols
like cosign.Signature, bundle.RekorBundle, client.Rekor, and models.LogEntry,
and then remove any imports that are no longer needed so the file reflects
actual runtime dependencies.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@cmd/sign-object/main.go`:
- Line 549: The help text in sign-object’s CLI output still points to a missing
docs target, so update the reference in main.go where the usage/help string is
built to use docs/features/profile-signing-and-tamper-detection.md instead of
the broken signing README path. Make sure the updated text appears in the same
help-message/usage block that prints “For more information” so sign-object
--help shows a valid link.

In `@go.mod`:
- Around line 51-52: The dependency on github.com/sigstore/rekor is still pinned
to the vulnerable 1.5.0 release; update the rekor entry in go.mod to 1.5.2 or
newer while leaving github.com/sigstore/fulcio as-is. Make sure the module
version change is reflected wherever the rekor dependency is declared so the
project no longer resolves to the affected release.

In `@pkg/signature/cosign_adapter_test.go`:
- Around line 128-142: The “Certificate is CA” subtest in cosign_adapter_test.go
is not actually reaching the CA-check in VerifyData because it feeds raw DER
into Signature.Certificate and ignores CreateCertificate errors, so the failure
can come from the empty-cert or public-key path instead. Update this test to
generate a valid certificate with x509.CreateCertificate, ensure it has required
fields like SerialNumber so creation succeeds, PEM-encode the resulting cert
before assigning it to Signature.Certificate, and then assert the specific
CA-rejection error from adapter.VerifyData so the subtest exercises the intended
cert.IsCA branch.

In `@pkg/signature/cosign_adapter.go`:
- Around line 449-459: In cosign_adapter.go, the strict verification logic in
the Rekor/CT evidence check is rejecting ambient OIDC keyless signatures because
signKeyless does not populate sig.RekorBundle, while only the hard-coded
interactive issuer is exempted. Update the verification path around the
sig.RekorBundle / sig.Issuer checks so ambient workload-identity issuers are
either given Rekor evidence during signing or explicitly treated as valid in
strict mode, and keep the policy consistent with signKeyless and the strict
verification branch.

---

Nitpick comments:
In `@cmd/sign-object/Dockerfile`:
- Around line 17-20: The final stage of the sign-object image still runs as
root; update the Dockerfile’s distroless runtime setup to use the built-in
nonroot user from gcr.io/distroless/static-debian13 before the ENTRYPOINT. Make
the change in the final image configuration so the container executes as UID
65532, and ensure the /work directory usage remains compatible with that user
for generate-keypair/sign outputs.

In `@pkg/objectcache/containerprofilecache/tamper_alert_test.go`:
- Around line 350-351: Remove the stale trailing comment in tamper_alert_test.go
that refers to a cfgRef config shim, since the strict-mode tests use
config.Config directly and no cfgRef type exists. Locate the leftover comment
near the strict-mode test setup around the existing config.Config usage, and
delete only that misleading note without changing the test logic.

In `@pkg/rulemanager/ruleswatcher/watcher.go`:
- Around line 90-108: The rules sync path in watcher.go is failing closed on
unsigned resources, which can silently remove all enabled rules when
EnableSignatureVerification is on. Update the RulesWatcher flow around
unstructuredToRules and verifyRules to make this behavior explicit: document
that unsigned resources are rejected, and add a higher-signal Warning or metric
in the skippedVerificationCount path when many or all enabled rules are skipped.
Keep the existing verifyRules and skippedByVerification accounting, but ensure
operators get visible feedback when rule coverage drops to near zero.

In `@pkg/signature/cosign_adapter.go`:
- Around line 232-234: The simulateKeyless method on CosignAdapter is dead code
and should be removed entirely rather than kept as a deprecation stub. Delete
the unused simulateKeyless function from cosign_adapter.go, and make sure no
remaining references in CosignAdapter or related signature flow still depend on
it; if any callers exist, update them to use the real keyless signing path
instead.
- Around line 37-45: The blank var _ references in cosign_adapter.go are only
keeping placeholder Rekor/Cosign imports alive and should be removed once real
usage is added or the flow is dropped. Update the cosign_adapter package by
cleaning out the unused symbols like cosign.Signature, bundle.RekorBundle,
client.Rekor, and models.LogEntry, and then remove any imports that are no
longer needed so the file reflects actual runtime dependencies.

In `@pkg/signature/sign_test.go`:
- Around line 194-208: The "Complete signature" test path in sign_test.go is
being skipped by default because it calls SignObjectKeyless behind the
ENABLE_KEYLESS_TESTS gate, so the positive GetObjectSignature branch never runs
in CI. Update the setupSign path in the test table/t.Run logic to use
SignObjectDisableKeyless instead of SignObjectKeyless for this subtest, keeping
the env-gated skip only for cases that truly require keyless signing. This
should make the success-case coverage run by default while preserving the
existing test structure around GetObjectSignature and the tt.setupSign flow.

In `@tests/component_test.go`:
- Around line 3370-3398: Remove the duplicated doc comment for
Test_30_TamperedSignedProfiles and keep only the single godoc block immediately
preceding the test function. Clean up the repeated comment text in the
component_test.go test section so the Test_30_TamperedSignedProfiles declaration
has just one unique documentation block attached to it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ce71f69f-fb9b-495d-b391-f54e08cfec6a

📥 Commits

Reviewing files that changed from the base of the PR and between 35e5523 and ea2d117.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (44)
  • .github/workflows/component-tests.yaml
  • cmd/main.go
  • cmd/sign-object/Dockerfile
  • cmd/sign-object/main.go
  • docs/features/profile-signing-and-tamper-detection.md
  • go.mod
  • pkg/config/config.go
  • pkg/containerprofilemanager/v1/lifecycle.go
  • pkg/exporters/alert_manager.go
  • pkg/objectcache/containerprofilecache/containerprofilecache.go
  • pkg/objectcache/containerprofilecache/projection.go
  • pkg/objectcache/containerprofilecache/tamper_alert.go
  • pkg/objectcache/containerprofilecache/tamper_alert_test.go
  • pkg/objectcache/containerprofilecache/test32_projection_test.go
  • pkg/objectcache/shared_container_data.go
  • pkg/rulemanager/cel/libraries/applicationprofile/ap.go
  • pkg/rulemanager/cel/libraries/cache/function_cache.go
  • pkg/rulemanager/ruleswatcher/watcher.go
  • pkg/rulemanager/ruleswatcher/watcher_signature_test.go
  • pkg/signature/annotations.go
  • pkg/signature/cluster_flow_test.go
  • pkg/signature/cluster_scenario_test.go
  • pkg/signature/cosign_adapter.go
  • pkg/signature/cosign_adapter_test.go
  • pkg/signature/interface.go
  • pkg/signature/profiles/adapter_test.go
  • pkg/signature/profiles/applicationprofile_adapter.go
  • pkg/signature/profiles/empty_typemeta_test.go
  • pkg/signature/profiles/networkneighborhood_adapter.go
  • pkg/signature/profiles/networkneighborhood_adapter_test.go
  • pkg/signature/profiles/rules_adapter.go
  • pkg/signature/profiles/rules_adapter_test.go
  • pkg/signature/profiles/seccompprofile_adapter.go
  • pkg/signature/sign.go
  • pkg/signature/sign_test.go
  • pkg/signature/signer.go
  • pkg/signature/verifier.go
  • pkg/signature/verify.go
  • pkg/signature/verify_test.go
  • tests/chart/templates/node-agent/default-rules.yaml
  • tests/component_test.go
  • tests/resources/aplint_test.go
  • tests/resources/curl-signed-deployment.yaml
  • tests/resources/known-application-profile.yaml

Comment thread cmd/sign-object/main.go
# Extract signature information
sign-object extract-signature --file signed-object.yaml

For more information, see: docs/signing/README.md`)

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
fd -t f 'README.md' docs/signing 2>/dev/null || echo "docs/signing/README.md not found"
fd -t f 'profile-signing-and-tamper-detection.md' docs

Repository: kubescape/node-agent

Length of output: 245


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the nearby help text in context
sed -n '530,560p' cmd/sign-object/main.go

# Check whether the old docs path is referenced anywhere else
rg -n "docs/signing/README\.md|profile-signing-and-tamper-detection\.md" .

Repository: kubescape/node-agent

Length of output: 910


Fix the help-text docs link

docs/signing/README.md is missing; update this to docs/features/profile-signing-and-tamper-detection.md so sign-object --help doesn’t advertise a broken reference.

🤖 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 `@cmd/sign-object/main.go` at line 549, The help text in sign-object’s CLI
output still points to a missing docs target, so update the reference in main.go
where the usage/help string is built to use
docs/features/profile-signing-and-tamper-detection.md instead of the broken
signing README path. Make sure the updated text appears in the same
help-message/usage block that prints “For more information” so sign-object
--help shows a valid link.

Comment thread go.mod
Comment on lines +51 to +52
github.com/sigstore/fulcio v1.8.5
github.com/sigstore/rekor v1.5.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
for pkg in "github.com/sigstore/cosign" "github.com/sigstore/fulcio" "github.com/sigstore/rekor" "github.com/sigstore/sigstore" "github.com/golang-jwt/jwt"; do
  echo "== $pkg =="
  gh api graphql -f query='
  query($q:String!){ securityVulnerabilities(first:5, ecosystem:GO, package:$q){ nodes{ advisory{summary severity} vulnerableVersionRange firstPatchedVersion{identifier} } } }' -f q="$pkg"
done

Repository: kubescape/node-agent

Length of output: 3495


🏁 Script executed:

#!/bin/bash
set -euo pipefail
nl -ba go.mod | sed -n '45,60p'

Repository: kubescape/node-agent

Length of output: 198


Bump github.com/sigstore/rekor off the vulnerable 1.5.0 release github.com/sigstore/rekor v1.5.0 is still in the high-severity OOM advisory range (< 1.5.2); update it to 1.5.2 or newer. github.com/sigstore/fulcio v1.8.5 is past the listed fix.

🤖 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 `@go.mod` around lines 51 - 52, The dependency on github.com/sigstore/rekor is
still pinned to the vulnerable 1.5.0 release; update the rekor entry in go.mod
to 1.5.2 or newer while leaving github.com/sigstore/fulcio as-is. Make sure the
module version change is reflected wherever the rekor dependency is declared so
the project no longer resolves to the affected release.

Comment on lines +128 to +142
t.Run("Certificate is CA", func(t *testing.T) {
// Create a CA certificate
template := x509.Certificate{
IsCA: true,
}
certDER, _ := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
sig := &Signature{
Signature: []byte("sig"),
Certificate: certDER,
}
err := adapter.VerifyData(data, sig, false)
if err == nil {
t.Error("Expected error for CA certificate, got nil")
}
})

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

This subtest never exercises the CA-rejection path.

Signature.Certificate is assigned raw DER bytes, but VerifyData runs pem.Decode first; on non-PEM input the block is nil and execution falls into the public-key branch, returning "untrusted public key rejected" rather than the cert.IsCA rejection. The discarded CreateCertificate error compounds this — without a SerialNumber the call likely fails, leaving certDER empty and triggering the "Certificate is empty" guard instead. The assertion passes for the wrong reason.

🧪 Proposed fix: PEM-encode a valid cert and assert the error
 	t.Run("Certificate is CA", func(t *testing.T) {
-		// Create a CA certificate
-		template := x509.Certificate{
-			IsCA: true,
-		}
-		certDER, _ := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
-		sig := &Signature{
-			Signature:   []byte("sig"),
-			Certificate: certDER,
-		}
+		// Create a CA certificate
+		template := x509.Certificate{
+			SerialNumber: big.NewInt(1),
+			IsCA:         true,
+		}
+		certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
+		if err != nil {
+			t.Fatalf("failed to create certificate: %v", err)
+		}
+		certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
+		sig := &Signature{
+			Signature:   []byte("sig"),
+			Certificate: certPEM,
+		}
 		err := adapter.VerifyData(data, sig, false)
 		if err == nil {
 			t.Error("Expected error for CA certificate, got nil")
 		}
 	})

Requires adding "crypto/rand", "encoding/pem", and "math/big" imports.

🤖 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 `@pkg/signature/cosign_adapter_test.go` around lines 128 - 142, The
“Certificate is CA” subtest in cosign_adapter_test.go is not actually reaching
the CA-check in VerifyData because it feeds raw DER into Signature.Certificate
and ignores CreateCertificate errors, so the failure can come from the
empty-cert or public-key path instead. Update this test to generate a valid
certificate with x509.CreateCertificate, ensure it has required fields like
SerialNumber so creation succeeds, PEM-encode the resulting cert before
assigning it to Signature.Certificate, and then assert the specific CA-rejection
error from adapter.VerifyData so the subtest exercises the intended cert.IsCA
branch.

Comment on lines +449 to +459
// Validate Rekor/CT evidence if Rekor bundle is present
if len(sig.RekorBundle) > 0 {
// In a full implementation, we would use cosign.VerifyBundle
// for now we acknowledge its presence for strict verification
} else if sig.Issuer != "local" && sig.Issuer != "" {
// For non-local certificates, we expect a Rekor bundle in strict mode
// But we'll allow it if we are in interactive mode (where Rekor might not be used)
if sig.Issuer != "https://oauth2.sigstore.dev/auth" {
return fmt.Errorf("strict verification failed: missing Rekor bundle for certificate from %q", sig.Issuer)
}
}

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 | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file outline ==\n'
ast-grep outline pkg/signature/cosign_adapter.go --view expanded || true

printf '\n== relevant slices ==\n'
sed -n '180,240p' pkg/signature/cosign_adapter.go
printf '\n---\n'
sed -n '430,480p' pkg/signature/cosign_adapter.go

printf '\n== search RekorBundle assignments/usages ==\n'
rg -n "RekorBundle|issuer|allowUntrusted|strict verification" pkg/signature -S

Repository: kubescape/node-agent

Length of output: 10052


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== verification tail ==\n'
sed -n '480,510p' pkg/signature/cosign_adapter.go

printf '\n== keyless signing header/body ==\n'
sed -n '130,230p' pkg/signature/cosign_adapter.go

printf '\n== strict verification tests/search ==\n'
rg -n "strict verification|missing Rekor bundle|allowUntrusted|keyless signature missing issuer or identity|useKeyless" pkg/signature -S

Repository: kubescape/node-agent

Length of output: 6423


Keyless signatures from ambient OIDC fail strict verification. signKeyless never sets sig.RekorBundle, so strict mode rejects workload-identity issuers such as GitHub Actions; only the hard-coded interactive issuer (https://oauth2.sigstore.dev/auth) bypasses that check. Either upload Rekor evidence or document that strict mode only works for the interactive keyless flow.

🤖 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 `@pkg/signature/cosign_adapter.go` around lines 449 - 459, In
cosign_adapter.go, the strict verification logic in the Rekor/CT evidence check
is rejecting ambient OIDC keyless signatures because signKeyless does not
populate sig.RekorBundle, while only the hard-coded interactive issuer is
exempted. Update the verification path around the sig.RekorBundle / sig.Issuer
checks so ambient workload-identity issuers are either given Rekor evidence
during signing or explicitly treated as valid in strict mode, and keep the
policy consistent with signKeyless and the strict verification branch.

@github-actions

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.214 0.215 +0.7%
Peak CPU (cores) 0.224 0.221 -1.5%
Avg Memory (MiB) 334.248 273.823 -18.1%
Peak Memory (MiB) 336.441 281.117 -16.4%
Dedup Effectiveness

No data available.

@matthyx matthyx moved this to WIP in KS PRs tracking Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted Created through Armosec AI tooling (armosec-shared-rules plugin)

Projects

Status: WIP

Development

Successfully merging this pull request may close these issues.

2 participants