-
Notifications
You must be signed in to change notification settings - Fork 64
wip: fix: deduplication of artifact and dependency references #869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…all command Signed-off-by: cannarelladev <cannarella.dev@gmail.com>
Signed-off-by: cannarelladev <cannarella.dev@gmail.com>
|
Welcome @cannarelladev! It looks like this is your first PR to falcosecurity/falcoctl 🎉 |
|
/milestone v0.12.0 |
Signed-off-by: cannarelladev <cannarella.dev@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes the deduplication logic for artifact and dependency references during the installation phase. Previously, falcoctl attempted to deduplicate artifacts but the logic was incorrect, leading to multiple pulls from the container registry for the same artifact.
Key changes:
- Refactored artifact preparation logic into a new
prepareArtifactListfunction that properly deduplicates user-provided artifact references before dependency resolution - Modified
ResolveDepsto accept separate resolvers for artifact configs and references, enabling proper resolution of dependency references
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| cmd/artifact/install/install.go | Extracted deduplication logic into new prepareArtifactList function; removed redundant resolvedRef variable usage throughout installation flow |
| cmd/artifact/install/deps.go | Added refResolver type; updated ResolveDeps signature to accept both config and ref resolvers; removed duplicate reference check for user inputs; added reference resolution for dependencies |
| cmd/artifact/install/deps_test.go | Updated test cases to use new configResolver naming and added refResolver to match new ResolveDeps signature |
| cmd/artifact/install/install_test.go | Removed trailing whitespace |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
cmd/artifact/install/install.go
Outdated
| func (o *artifactInstallOptions) prepareArtifactList(ctx context.Context, puller *puller.Puller, args []string) (refs []string, err error) { | ||
| logger := o.Printer.Logger | ||
|
|
||
| resolver := refResolver(func(ref string) (string, error) { | ||
| return o.IndexCache.ResolveReference(ref) | ||
| }) | ||
|
|
||
| configResolver := artifactConfigResolver(func(ref string) (*oci.RegistryResult, error) { | ||
| artifactConfig, err := puller.ArtifactConfig(ctx, ref, o.platformOS, o.platformArch) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| return &oci.RegistryResult{ | ||
| Config: *artifactConfig, | ||
| }, nil | ||
| }) | ||
|
|
||
| seen := make(map[string]struct{}, len(args)) | ||
| resolved := make([]string, 0, len(args)) | ||
|
|
||
| // Compute unique resolved references | ||
| for _, arg := range args { | ||
| ref, err := resolver(arg) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if _, ok := seen[ref]; ok { | ||
| continue | ||
| } | ||
| seen[ref] = struct{}{} | ||
| resolved = append(resolved, ref) | ||
| } |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new prepareArtifactList function implements the core deduplication logic that this PR is meant to fix. However, there are no tests that verify this deduplication behavior works correctly when duplicate artifact references are provided. Consider adding a test case that verifies duplicate artifacts (either exact duplicates or artifacts that resolve to the same reference) are properly deduplicated.
Signed-off-by: cannarelladev <cannarella.dev@gmail.com>
leogr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @cannarelladev
This is a great improvement! However, I found a couple of issues (see my comment below).
Furthermore, I have a doubt 🤔
This PR introduces a behavior change in how we handle an imperfect artifact's references list as input.
Previously, the user received a clear error when they supplied conflicting refs for the same artifact. Now, falcoctl will ignore duplicates, but the actual installed version will depend purely on argument order.
Since the intended goal here is to deduplicate, we might want to follow a predictable logic for which duplicate wins (e.g., "highest version wins" rather than “last argument wins”). Using the highest compatible version is a pattern we already used for alternative dependencies, and I guess it should work in this case as well.
cmd/artifact/install/install.go
Outdated
|
|
||
| if signatures[resolvedRef] == nil { | ||
| if signatures[ref] == nil { | ||
| if sig := o.IndexCache.SignatureForIndexRef(ref); sig != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this change, now we pass full references to SignatureForIndexRef(), which by design returns nil for full refs. As a result, the signature verification is effectively skipped every time, even when it exists in the index.
Now:
❯ ./falcoctl artifact install k8saudit k8saudit-rules
2025-12-23 11:29:45 INFO Resolving dependencies ...
2025-12-23 11:29:48 INFO Installing artifacts
└ refs: [ghcr.io/falcosecurity/plugins/plugin/k8saudit:latest ghcr.io/falcosecurity/plugins/ruleset/k8saudit:latest ghcr.io/falcosecurity/plugins/plugin/json:0.7.0]
2025-12-23 11:29:48 INFO Preparing to pull artifact ref: ghcr.io/falcosecurity/plugins/plugin/k8saudit:latest
2025-12-23 11:29:48 INFO Pulling layer 78495c93d6f6
2025-12-23 11:29:49 INFO Pulling layer 163468d93bfc
2025-12-23 11:29:49 INFO Pulling layer 37afdf131d6f
2025-12-23 11:29:49 ERROR cannot use directory "/usr/share/falco/plugins" as install destination: /usr/share/falco/plugins is not writable
Before:
❯ falcoctl artifact install k8saudit k8saudit-rules
2025-12-23 12:01:39 INFO Resolving dependencies ...
2025-12-23 12:01:42 INFO Installing artifacts
└ refs: [ghcr.io/falcosecurity/plugins/plugin/k8saudit:latest ghcr.io/falcosecurity/plugins/ruleset/k8saudit:latest json:0.7.0]
2025-12-23 12:01:42 INFO Preparing to pull artifact ref: ghcr.io/falcosecurity/plugins/plugin/k8saudit:latest
2025-12-23 12:01:43 INFO Pulling layer 78495c93d6f6
2025-12-23 12:01:43 INFO Pulling layer 163468d93bfc
2025-12-23 12:01:43 INFO Pulling layer 37afdf131d6f
2025-12-23 12:01:43 INFO Verifying signature for artifact
└ digest: ghcr.io/falcosecurity/plugins/plugin/k8saudit@sha256:7310019ee3b7f89d503df7e50db15fbe771b4e003125782960fd0e8da43b0905
2025-12-23 12:01:44 INFO Signature successfully verified!
2025-12-23 12:01:44 ERROR cannot use directory "/usr/share/falco/plugins" as install destination: /usr/share/falco/plugins is not writable
N.B. Ignore the error, I just didn't use sudo. The point is that the Verifying signature for artifact step is no longer happening.
Further note, I can't recall why SignatureForIndexRef() can't work if we have a full reference. It may be worth investigating the reasons for that, or whether it could be improved to accept full references as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed: the implementation now reuses an existing data structure to store all artifact names for SignatureForIndexRef().
Additionally, the behavior of falcoctl artifact install when duplicate references are provided is not defined anywhere in the repository. Previously, this resulted in an error; now, duplicates are handled by selecting the highest version.
| if alternativeVer.Compare(*existing.ver) > 0 { | ||
| if err := upsertMap(alternative.Name + ":" + alternativeVer.String()); err != nil { | ||
| return nil, err | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this changeset, this function took a single artifactConfigResolver and assumed it resolved references by calling IndexCache.ResolveReference(ref). Now we need to explicitly call resolver before inserting it in the map.
This is correctly handled for primary deps (see line 173 below), but we are missing the resolver call here for alternative deps.
Indeed, if we try to install k8saudit-eks:0.2.1 together with k8saudit-rules (which, among alternatives, declares k8saudit-eks:0.4.0) we see the problem:
❯ ./falcoctl artifact install k8saudit-eks:0.2.1 k8saudit-rules
2025-12-23 14:01:21 INFO Resolving dependencies ...
2025-12-23 14:01:24 ERROR unable to create new repository with ref k8saudit-eks:0.4.0: invalid reference: missing registry or repository
Before, the alternative dependency was correctly resolved:
❯ falcoctl artifact install k8saudit-eks:0.2.1 k8saudit-rules
2025-12-23 14:01:08 INFO Resolving dependencies ...
2025-12-23 14:01:12 INFO Installing artifacts refs: [k8saudit-eks:0.4.0 ghcr.io/falcosecurity/plugins/ruleset/k8saudit:latest json:0.7.0]
2025-12-23 14:01:12 INFO Preparing to pull artifact ref: ghcr.io/falcosecurity/plugins/plugin/k8saudit-eks:0.4.0
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the decoupling between "resolver" and pull of "configResolver" is intentional, in fact the goal is to avoid that inside the ResolveDeps the inRefs will be resolved again (they are already resolved).
Anyway the described behavior about the alternative reference it's a bug. I'm fixing it resolving properly the ref before upserting the map.
…ve artifact reference, add tests to prepareArtifactList Signed-off-by: cannarelladev <cannarella.dev@gmail.com>
86e89b3 to
8ce8d13
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: c2ndev The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
What type of PR is this?
/kind bug
Any specific area of the project related to this PR?
/area cli
What this PR does / why we need it:
This PR fixes an incorrect behavior during the artifact installation phase.
During this step,
falcoctlattempts to deduplicate artifact and dependency references to avoid multiple pulls from the container registry.However, this deduplication currently does not work correctly.
Which issue(s) this PR fixes:
Fixes #868
Special notes for your reviewer: