Skip to content

feat: add scanfailure types for scan failure reporting#620

Merged
kooomix merged 2 commits into
mainfrom
feature/SUB-7105-scanfailure-types
Mar 15, 2026
Merged

feat: add scanfailure types for scan failure reporting#620
kooomix merged 2 commits into
mainfrom
feature/SUB-7105-scanfailure-types

Conversation

@kooomix
Copy link
Copy Markdown
Contributor

@kooomix kooomix commented Mar 15, 2026

Summary

  • Add scanfailure package with scan failure report types (ScanFailureReport, ScanFailureCase, WorkloadIdentifier)
  • These types define the HTTP POST payload for /k8s/v2/vulnScanFailure (careportreceiver endpoint)
  • Moved from kubescape/messaging to armoapi-go as the canonical home for API contract types

Context

Part of SUB-7074 (scan failure notifications). kubevuln (B.2) and node-agent (B.5) will import these types to report scan failures. All consuming repos already depend on armoapi-go — no new dependency edges.

Test plan

  • go build ./scanfailure/... passes
  • After merge, update imports in: messaging, event-ingester-service, users-notification-service

Summary by CodeRabbit

  • New Features
    • Added scan failure reporting infrastructure to track and categorize scan failures across multiple scenarios: CVE analysis issues, SBOM generation failures, resource constraints, and backend processing errors. System now captures affected workloads and images to enable detailed failure diagnostics and reporting.

Move scan failure report types (ScanFailureReport, ScanFailureCase,
WorkloadIdentifier) to armoapi-go as the canonical home for API
contract types. Previously in kubescape/messaging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 15, 2026 08:31
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 15, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e5c4c4cc-3408-44ba-b534-2eaaa1ce1e72

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A new Go file introduces type definitions for scan failure reporting in a scanner system. It defines a ScanFailureCase enum with four failure types, a WorkloadIdentifier struct to identify affected Kubernetes workloads, and a ScanFailureReport struct that contains per-image failure information including customer ID, workloads, image tag, failure reason, and timestamp.

Changes

Cohort / File(s) Summary
Scan Failure Types
scanfailure/types.go
Introduces ScanFailureCase enum with four concrete values (CVE, SBOM Generation, OOM Killed, Backend Post) and String() method. Defines WorkloadIdentifier struct with cluster, namespace, kind, and name fields. Introduces ScanFailureReport struct containing customer GUID, workload list, image tag, failure case/reason, timestamp, registry context, and registry-scan flag, all with JSON/BSON tags.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A scanner's woes now neatly stored,
With types and cases all adored,
CVEs and SBOMs in enums bright,
Workloads identified just right!
Failure reports hop through the system clean. 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and concisely summarizes the main change: adding scanfailure types for scan failure reporting, which is the primary purpose of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/SUB-7105-scanfailure-types
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new scanfailure package defining shared data structures for reporting container scan failures (including failure categorization and affected workload context) so downstream services can consume a consistent schema.

Changes:

  • Introduces ScanFailureCase enum with a String() helper for human-readable descriptions.
  • Adds WorkloadIdentifier and ScanFailureReport structs with JSON/BSON tags for transport/storage.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread scanfailure/types.go
Comment on lines +9 to +21
// ScanFailureCVE — have SBOM, can't match against vulnerability DBs.
ScanFailureCVE ScanFailureCase = 1
// ScanFailureSBOMGeneration — can't build SBOM from image.
ScanFailureSBOMGeneration ScanFailureCase = 2
// ScanFailureOOMKilled — scanner process was OOM-killed.
ScanFailureOOMKilled ScanFailureCase = 3
// ScanFailureBackendPost — scan succeeded but results couldn't be posted.
ScanFailureBackendPost ScanFailureCase = 4
)

// String returns a human-readable description of the failure case.
func (f ScanFailureCase) String() string {
switch f {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in efa4ba6. Added ScanFailureUnknown = 0 as explicit zero value.

Comment thread scanfailure/types.go Outdated
case ScanFailureSBOMGeneration:
return "SBOM generation failed"
case ScanFailureOOMKilled:
return "Scanner process OOM killed"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in efa4ba6. Changed to "OOM-killed" to match the constant name ScanFailureOOMKilled.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
scanfailure/types.go (1)

37-42: Avoid long-term schema drift between WorkloadIdentifier and armotypes.Resource.

Line 37-Line 42 introduce a second workload identity model with overlapping semantics (cluster/namespace/kind/name). This increases drift risk across services. Consider adding explicit conversion helpers to/from armotypes.Resource so there is one canonical internal shape even if wire tags differ.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scanfailure/types.go` around lines 37 - 42, WorkloadIdentifier duplicates
armotypes.Resource shape; add explicit conversion helpers to avoid schema drift
by implementing two functions (e.g., WorkloadIdentifier.ToArmResource()
armotypes.Resource and NewWorkloadIdentifierFromArm(res armotypes.Resource)
WorkloadIdentifier) that map ClusterName/Namespace/WorkloadKind/WorkloadName ↔
corresponding armotypes.Resource fields, place them alongside the
WorkloadIdentifier type (or in a nearby conversions file), and use these helpers
across codepaths so the canonical internal representation remains
armotypes.Resource while WorkloadIdentifier only handles wire/tag differences.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scanfailure/types.go`:
- Around line 48-59: Add a Validate method on ScanFailureReport that enforces
the documented invariants: if IsRegistryScan is true then Workloads must be
empty/nil and RegistryName must be non-empty, and if IsRegistryScan is false
then RegistryName must be empty (or optional) and Workloads must be non-empty;
the method should return an error describing which invariant failed (use
ScanFailureReport.Validate) and be called wherever reports are constructed or
serialized (e.g., before sending or marshalling) so malformed reports cannot be
emitted. Ensure the checks handle nil/zero slices and trim/check RegistryName
for emptiness and use clear error messages mentioning the field names.

---

Nitpick comments:
In `@scanfailure/types.go`:
- Around line 37-42: WorkloadIdentifier duplicates armotypes.Resource shape; add
explicit conversion helpers to avoid schema drift by implementing two functions
(e.g., WorkloadIdentifier.ToArmResource() armotypes.Resource and
NewWorkloadIdentifierFromArm(res armotypes.Resource) WorkloadIdentifier) that
map ClusterName/Namespace/WorkloadKind/WorkloadName ↔ corresponding
armotypes.Resource fields, place them alongside the WorkloadIdentifier type (or
in a nearby conversions file), and use these helpers across codepaths so the
canonical internal representation remains armotypes.Resource while
WorkloadIdentifier only handles wire/tag differences.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 08a748c8-e4aa-4e46-9ff2-f58a03f5e1be

📥 Commits

Reviewing files that changed from the base of the PR and between b9b82d8 and d37ab40.

📒 Files selected for processing (1)
  • scanfailure/types.go

Comment thread scanfailure/types.go
Comment on lines +48 to +59
type ScanFailureReport struct {
CustomerGUID string `json:"customerGUID" bson:"customerGUID"`
Workloads []WorkloadIdentifier `json:"workloads,omitempty" bson:"workloads,omitempty"`
ImageTag string `json:"imageTag" bson:"imageTag"`
FailureCase ScanFailureCase `json:"failureCase" bson:"failureCase"`
FailureReason string `json:"failureReason" bson:"failureReason"`
Timestamp time.Time `json:"timestamp" bson:"timestamp"`

// Registry scan context (no workloads).
RegistryName string `json:"registryName,omitempty" bson:"registryName,omitempty"`
IsRegistryScan bool `json:"isRegistryScan,omitempty" bson:"isRegistryScan,omitempty"`
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Mar 15, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Enforce registry/workload payload invariants in code, not only comments.

Line 47 documents strict rules (registry scan => no workloads + registryName set), but Line 49-Line 59 does not enforce them. Invalid combinations can be serialized and sent downstream.

Proposed guardrail (`Validate`) to prevent malformed reports
 package scanfailure
 
-import "time"
+import (
+	"fmt"
+	"time"
+)
@@
 type ScanFailureReport struct {
@@
 	IsRegistryScan bool   `json:"isRegistryScan,omitempty" bson:"isRegistryScan,omitempty"`
 }
+
+func (r ScanFailureReport) Validate() error {
+	if r.IsRegistryScan {
+		if r.RegistryName == "" {
+			return fmt.Errorf("registryName must be set when isRegistryScan is true")
+		}
+		if len(r.Workloads) > 0 {
+			return fmt.Errorf("workloads must be empty when isRegistryScan is true")
+		}
+		return nil
+	}
+	if len(r.Workloads) == 0 {
+		return fmt.Errorf("workloads must be set when isRegistryScan is false")
+	}
+	if r.RegistryName != "" {
+		return fmt.Errorf("registryName must be empty when isRegistryScan is false")
+	}
+	return nil
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scanfailure/types.go` around lines 48 - 59, Add a Validate method on
ScanFailureReport that enforces the documented invariants: if IsRegistryScan is
true then Workloads must be empty/nil and RegistryName must be non-empty, and if
IsRegistryScan is false then RegistryName must be empty (or optional) and
Workloads must be non-empty; the method should return an error describing which
invariant failed (use ScanFailureReport.Validate) and be called wherever reports
are constructed or serialized (e.g., before sending or marshalling) so malformed
reports cannot be emitted. Ensure the checks handle nil/zero slices and
trim/check RegistryName for emptiness and use clear error messages mentioning
the field names.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Keeping the type as a plain data struct for now. Validation logic (registry vs workload invariants) lives in the consuming services (event-ingester, kubevuln) where the context for those rules exists. Adding it here would couple the contract type to service-level business rules. Happy to revisit if we see validation bugs downstream.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@kooomix, that's a reasonable design boundary — keeping contract types as plain structs and pushing invariant enforcement into the services that own the construction context is a well-established pattern. Acknowledged, and thanks for the clear explanation.


✏️ Learnings added
Learnt from: kooomix
Repo: armosec/armoapi-go PR: 620
File: scanfailure/types.go:50-61
Timestamp: 2026-03-15T08:43:31.934Z
Learning: In the `armoapi-go` repository, the `scanfailure` package (file `scanfailure/types.go`) intentionally defines `ScanFailureReport` and related types as plain data structs with no validation logic. Registry vs. workload invariants (e.g., `IsRegistryScan=true` requires `RegistryName` set and empty `Workloads`) are enforced in the consuming services (`event-ingester`, `kubevuln`), not in the contract type itself. Do not suggest adding a `Validate()` method or other business-rule enforcement to this package.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Address review comments: add explicit zero-value constant for Go
safety, and fix "OOM killed" → "OOM-killed" inconsistency in String().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants