trust: switch policy.json lookup to configfile

Use shared configfile instead of custom policy.json path handling.
This updates ocipull to rely on signature.DefaultPolicy(), removes
explicit SignaturePolicyPath, and replaces trust's custom default-policy
path logic with common configfile code.

Replace hidden `--policypath` with --signature-policy` and require
it for `trust set` command instead of path resolution based on
configfile.

For `trust get`, the `--signature-policy` is optional.

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
This commit is contained in:
Jan Kaluza committed 2026-04-20 15:11:22 +02:00
1 parent 34a4633d5f
commit 54d61c2f02
28 files changed
+167 -268

No files matched your search

+3 -2
View File
@@ -35,8 +35,9 @@ func init() {
Parent: trustCmd, Parent: trustCmd,
}) })
setFlags := setTrustCommand.Flags() setFlags := setTrustCommand.Flags()
setFlags.StringVar(&setOptions.PolicyPath, "policypath", "", "") signaturePolicyFlagName := "signature-policy"
_ = setFlags.MarkHidden("policypath") setFlags.StringVar(&setOptions.PolicyPath, signaturePolicyFlagName, "", "Path to a signature-policy file")
_ = setTrustCommand.RegisterFlagCompletionFunc(signaturePolicyFlagName, completion.AutocompleteDefault)
pubkeysfileFlagName := "pubkeysfile" pubkeysfileFlagName := "pubkeysfile"
setFlags.StringArrayVarP(&setOptions.PubKeysFile, pubkeysfileFlagName, "f", []string{}, `Path of installed public key(s) to trust for TARGET. setFlags.StringArrayVarP(&setOptions.PubKeysFile, pubkeysfileFlagName, "f", []string{}, `Path of installed public key(s) to trust for TARGET.
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v6/cmd/podman/registry" "github.com/containers/podman/v6/cmd/podman/registry"
"github.com/containers/podman/v6/pkg/domain/entities" "github.com/containers/podman/v6/pkg/domain/entities"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"go.podman.io/common/pkg/completion"
"go.podman.io/common/pkg/report" "go.podman.io/common/pkg/report"
) )
@@ -35,9 +36,9 @@ func init() {
}) })
showFlags := showTrustCommand.Flags() showFlags := showTrustCommand.Flags()
showFlags.BoolVarP(&showTrustOptions.JSON, "json", "j", false, "Output as json") showFlags.BoolVarP(&showTrustOptions.JSON, "json", "j", false, "Output as json")
showFlags.StringVar(&showTrustOptions.PolicyPath, "policypath", "", "") showFlags.StringVar(&showTrustOptions.PolicyPath, "signature-policy", "", "Path to a signature-policy file")
_ = showTrustCommand.RegisterFlagCompletionFunc("signature-policy", completion.AutocompleteDefault)
showFlags.BoolVar(&showTrustOptions.Raw, "raw", false, "Output raw policy file") showFlags.BoolVar(&showTrustOptions.Raw, "raw", false, "Output raw policy file")
_ = showFlags.MarkHidden("policypath")
showFlags.StringVar(&showTrustOptions.RegistryPath, "registrypath", "", "") showFlags.StringVar(&showTrustOptions.RegistryPath, "registrypath", "", "")
showFlags.BoolVarP(&noHeading, "noheading", "n", false, "Do not print column headings") showFlags.BoolVarP(&noHeading, "noheading", "n", false, "Do not print column headings")
_ = showFlags.MarkHidden("registrypath") _ = showFlags.MarkHidden("registrypath")
@@ -55,6 +55,9 @@ Trust may be updated using the command **podman image trust set** for an existin
are referenced in policy.json. Any path to a file may be used but locating the file in **/etc/pki/containers** is recommended. Options may be used multiple times to are referenced in policy.json. Any path to a file may be used but locating the file in **/etc/pki/containers** is recommended. Options may be used multiple times to
require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** and **sigstoreSigned** types. require an image be signed by multiple keys. The **--pubkeysfile** option is required for the **signedBy** and **sigstoreSigned** types.
#### **--signature-policy**=*path*
Path to the signature policy file (**policy.json**) that Podman updates. This option is required for **set**.
#### **--type**, **-t**=*value* #### **--type**, **-t**=*value*
The trust type for this policy entry. The trust type for this policy entry.
Accepted values: Accepted values:
@@ -76,16 +79,19 @@ Trust may be updated using the command **podman image trust set** for an existin
#### **--raw** #### **--raw**
Output trust policy file as raw JSON Output trust policy file as raw JSON
#### **--signature-policy**=*path*
Path to the signature policy file (**policy.json**) to display. When omitted, Podman resolves the policy path from the system configuration the same way it selects a policy for image pulls.
## EXAMPLES ## EXAMPLES
Accept all unsigned images from a registry: Accept all unsigned images from a registry:
``` ```
sudo podman image trust set --type accept docker.io sudo podman image trust set --signature-policy /etc/containers/policy.json --type accept docker.io
``` ```
Modify default trust policy: Modify default trust policy:
``` ```
sudo podman image trust set -t reject default sudo podman image trust set --signature-policy /etc/containers/policy.json -t reject default
``` ```
Display system trust policy: Display system trust policy:
+3 -3
View File
@@ -64,9 +64,9 @@ require (
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
github.com/vbauerster/mpb/v8 v8.12.0 github.com/vbauerster/mpb/v8 v8.12.0
github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netlink v1.3.1
go.podman.io/common v0.67.2-0.20260416202057-7d53666cdee9 go.podman.io/common v0.67.2-0.20260420103546-618304d6f83d
go.podman.io/image/v5 v5.39.3-0.20260416202057-7d53666cdee9 go.podman.io/image/v5 v5.39.3-0.20260420103546-618304d6f83d
go.podman.io/storage v1.62.1-0.20260416202057-7d53666cdee9 go.podman.io/storage v1.62.1-0.20260420103546-618304d6f83d
golang.org/x/crypto v0.50.0 golang.org/x/crypto v0.50.0
golang.org/x/net v0.53.0 golang.org/x/net v0.53.0
golang.org/x/sync v0.20.0 golang.org/x/sync v0.20.0
+6 -6
View File
@@ -429,12 +429,12 @@ go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
go.podman.io/common v0.67.2-0.20260416202057-7d53666cdee9 h1:WOO740hWFwfvA+vcpXO9TaW9v/kMzWSiEx8Ulb0kX4U= go.podman.io/common v0.67.2-0.20260420103546-618304d6f83d h1:zryioAYWqUu1BUPraJJ6q5mLiclNZ3kTuQyyBO/5vYs=
go.podman.io/common v0.67.2-0.20260416202057-7d53666cdee9/go.mod h1:PIlj/bShUaMV9Dz4ygGPtUWZ3Zx4nukPO82Q/AnZrRA= go.podman.io/common v0.67.2-0.20260420103546-618304d6f83d/go.mod h1:Pom4Io+8C+CCZzr3CRUkr6A5inTMY8nVaFS3X1Y5NbI=
go.podman.io/image/v5 v5.39.3-0.20260416202057-7d53666cdee9 h1:7R6x8/GH9BprC+VjmU8BhGGxn9w/AZBmJqMm059S9s0= go.podman.io/image/v5 v5.39.3-0.20260420103546-618304d6f83d h1:NeMM89Fwaw19guPj/hXEjBtoCeH/mGgbAWoBnpnRiIo=
go.podman.io/image/v5 v5.39.3-0.20260416202057-7d53666cdee9/go.mod h1:E3RVHxc/Hmyq3U4DUpv+MSdmk/tkmAcSjp61K6YmAIU= go.podman.io/image/v5 v5.39.3-0.20260420103546-618304d6f83d/go.mod h1:Yl9kZ8QslAOPc2rMkCrjPENCpSox6frxScCEzpmsQX4=
go.podman.io/storage v1.62.1-0.20260416202057-7d53666cdee9 h1:JK0umBWWQSgd8cx1YgOQeiIwtLTprW+iZrNKUxZX5kM= go.podman.io/storage v1.62.1-0.20260420103546-618304d6f83d h1:aMAdj9gLrVUz+Zb+nOxcoeT6+CC+8Rk2lHs1MC3kcQM=
go.podman.io/storage v1.62.1-0.20260416202057-7d53666cdee9/go.mod h1:13aOBf6782/fbAzH7QNEqlVzFu+X4sS4MxDM/VdJGZU= go.podman.io/storage v1.62.1-0.20260420103546-618304d6f83d/go.mod h1:13aOBf6782/fbAzH7QNEqlVzFu+X4sS4MxDM/VdJGZU=
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
-1
View File
@@ -439,7 +439,6 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
if runtime.imageContext.BigFilesTemporaryDir == "" { if runtime.imageContext.BigFilesTemporaryDir == "" {
runtime.imageContext.BigFilesTemporaryDir = parse.GetTempDir() runtime.imageContext.BigFilesTemporaryDir = parse.GetTempDir()
} }
runtime.imageContext.SignaturePolicyPath = runtime.config.Engine.SignaturePolicyPath
// Get us at least one working OCI runtime. // Get us at least one working OCI runtime.
runtime.ociRuntimes = make(map[string]OCIRuntime) runtime.ociRuntimes = make(map[string]OCIRuntime)
+1 -6
View File
@@ -100,6 +100,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
} }
func CommitContainer(w http.ResponseWriter, r *http.Request) { func CommitContainer(w http.ResponseWriter, r *http.Request) {
var err error
decoder := utils.GetDecoder(r) decoder := utils.GetDecoder(r)
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
@@ -121,17 +122,11 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
return return
} }
rtc, err := runtime.GetConfig()
if err != nil {
utils.Error(w, http.StatusInternalServerError, fmt.Errorf("Decode(): %w", err))
return
}
sc := runtime.SystemContext() sc := runtime.SystemContext()
options := libpod.ContainerCommitOptions{ options := libpod.ContainerCommitOptions{
Pause: true, Pause: true,
} }
options.CommitOptions = buildah.CommitOptions{ options.CommitOptions = buildah.CommitOptions{
SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
ReportWriter: os.Stderr, ReportWriter: os.Stderr,
SystemContext: sc, SystemContext: sc,
PreferredManifestType: manifest.DockerV2Schema2MediaType, PreferredManifestType: manifest.DockerV2Schema2MediaType,
+1 -6
View File
@@ -487,6 +487,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
var ( var (
destImage string destImage string
mimeType string mimeType string
err error
) )
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
@@ -510,11 +511,6 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
return return
} }
rtc, err := runtime.GetConfig()
if err != nil {
utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to get runtime config: %w", err))
return
}
sc := runtime.SystemContext() sc := runtime.SystemContext()
tag := "latest" tag := "latest"
options := libpod.ContainerCommitOptions{ options := libpod.ContainerCommitOptions{
@@ -534,7 +530,6 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
return return
} }
options.CommitOptions = buildah.CommitOptions{ options.CommitOptions = buildah.CommitOptions{
SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
ReportWriter: os.Stderr, ReportWriter: os.Stderr,
SystemContext: sc, SystemContext: sc,
PreferredManifestType: mimeType, PreferredManifestType: mimeType,
-5
View File
@@ -642,10 +642,6 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
if err != nil { if err != nil {
return nil, err return nil, err
} }
rtc, err := ic.Libpod.GetConfig()
if err != nil {
return nil, err
}
switch options.Format { switch options.Format {
case "oci": case "oci":
mimeType = buildah.OCIv1ImageManifest mimeType = buildah.OCIv1ImageManifest
@@ -670,7 +666,6 @@ func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrID string,
} }
} }
coptions := buildah.CommitOptions{ coptions := buildah.CommitOptions{
SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
ReportWriter: options.Writer, ReportWriter: options.Writer,
SystemContext: sc, SystemContext: sc,
PreferredManifestType: mimeType, PreferredManifestType: mimeType,
+51 -10
View File
@@ -6,20 +6,63 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"path/filepath"
"github.com/containers/podman/v6/pkg/domain/entities" "github.com/containers/podman/v6/pkg/domain/entities"
"github.com/containers/podman/v6/pkg/trust" "github.com/containers/podman/v6/pkg/trust"
"github.com/sirupsen/logrus"
"go.podman.io/image/v5/types"
"go.podman.io/storage/pkg/configfile"
"go.podman.io/storage/pkg/homedir"
) )
// policyPathFromConfigfile resolves policy.json the same way as [signature.DefaultPolicy]
// (via [configfile.Read]); overridePath, if non-empty, wins.
func policyPathFromConfigfile(sys *types.SystemContext, overridePath string) string {
if overridePath != "" {
return overridePath
}
if sys != nil && sys.SignaturePolicyPath != "" {
return sys.SignaturePolicyPath
}
root := ""
if sys != nil {
root = sys.RootForImplicitAbsolutePaths
}
policyFiles := configfile.File{
Name: "policy",
Extension: "json",
DoNotLoadDropInFiles: true,
EnvironmentName: "CONTAINERS_POLICY_JSON",
RootForImplicitAbsolutePaths: root,
ErrorIfNotFound: false,
}
for item, err := range configfile.Read(&policyFiles) {
if err != nil {
logrus.Warnf("Resolving default policy path: %v", err)
break
}
if item != nil {
return item.Name
}
}
userDir, err := configfile.UserConfigPath()
if err != nil {
logrus.Warnf("Error resolving user config path for policy: %v", err)
return filepath.Join(homedir.Get(), filepath.FromSlash(".config/containers/policy.json"))
}
return filepath.Join(userDir, "policy.json")
}
func (ir *ImageEngine) ShowTrust(_ context.Context, _ []string, options entities.ShowTrustOptions) (*entities.ShowTrustReport, error) { func (ir *ImageEngine) ShowTrust(_ context.Context, _ []string, options entities.ShowTrustOptions) (*entities.ShowTrustReport, error) {
var ( var (
err error err error
report entities.ShowTrustReport report entities.ShowTrustReport
) )
policyPath := trust.DefaultPolicyPath(ir.Libpod.SystemContext()) policyPath := policyPathFromConfigfile(ir.Libpod.SystemContext(), options.PolicyPath)
if len(options.PolicyPath) > 0 {
policyPath = options.PolicyPath
}
report.Raw, err = os.ReadFile(policyPath) report.Raw, err = os.ReadFile(policyPath)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -42,14 +85,12 @@ func (ir *ImageEngine) SetTrust(_ context.Context, args []string, options entiti
if len(args) != 1 { if len(args) != 1 {
return fmt.Errorf("SetTrust called with unexpected %d args", len(args)) return fmt.Errorf("SetTrust called with unexpected %d args", len(args))
} }
if options.PolicyPath == "" {
return fmt.Errorf("signature-policy path must be provided")
}
scope := args[0] scope := args[0]
policyPath := trust.DefaultPolicyPath(ir.Libpod.SystemContext()) return trust.AddPolicyEntries(options.PolicyPath, trust.AddPolicyEntriesInput{
if len(options.PolicyPath) > 0 {
policyPath = options.PolicyPath
}
return trust.AddPolicyEntries(policyPath, trust.AddPolicyEntriesInput{
Scope: scope, Scope: scope,
Type: options.Type, Type: options.Type,
PubKeyFiles: options.PubKeysFile, PubKeyFiles: options.PubKeysFile,
-33
View File
@@ -1,33 +0,0 @@
package ocipull
import (
"os"
"path/filepath"
"github.com/sirupsen/logrus"
)
// DefaultPolicyJSONPath should be overwritten at build time with the real path to the directory where
// the shipped policy.json file is located. This can either be absolute path or a relative path. If it
// is relative it will be resolved relative to the podman binary and NOT the CWD.
//
// use "-X github.com/containers/podman/v6/pkg/machine/ocipull.DefaultPolicyJSONPath=/somepath" in go ldflags to overwrite this
var DefaultPolicyJSONPath = ""
const policyfile = "policy.json"
// policyPaths returns a slice of possible directories where a policy.json might live
func policyPaths() []string {
paths := localPolicyOverwrites()
if DefaultPolicyJSONPath != "" {
if filepath.IsAbs(DefaultPolicyJSONPath) {
return append(paths, filepath.Join(DefaultPolicyJSONPath, policyfile))
}
p, err := os.Executable()
if err != nil {
logrus.Warnf("could not resolve relative path to binary: %q", err)
}
paths = append(paths, filepath.Join(filepath.Dir(p), DefaultPolicyJSONPath, policyfile))
}
return paths
}
-19
View File
@@ -1,19 +0,0 @@
//go:build !windows
package ocipull
import (
"path/filepath"
"go.podman.io/common/pkg/config"
"go.podman.io/storage/pkg/homedir"
)
func localPolicyOverwrites() []string {
var dirs []string
if p, err := homedir.GetConfigHome(); err == nil {
dirs = append(dirs, filepath.Join(p, "containers", policyfile))
}
dirs = append(dirs, config.DefaultSignaturePolicyPath)
return dirs
}
-10
View File
@@ -1,10 +0,0 @@
package ocipull
import (
"os"
"path/filepath"
)
func localPolicyOverwrites() []string {
return []string{filepath.Join(os.Getenv("APPDATA"), "containers", policyfile)}
}
+5 -14
View File
@@ -4,7 +4,6 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/fs"
"os" "os"
"github.com/containers/buildah/pkg/parse" "github.com/containers/buildah/pkg/parse"
@@ -14,6 +13,7 @@ import (
"go.podman.io/image/v5/oci/layout" "go.podman.io/image/v5/oci/layout"
"go.podman.io/image/v5/signature" "go.podman.io/image/v5/signature"
"go.podman.io/image/v5/types" "go.podman.io/image/v5/types"
"go.podman.io/storage/pkg/configfile"
) )
// pullOptions includes data to alter certain knobs when pulling a source // pullOptions includes data to alter certain knobs when pulling a source
@@ -48,7 +48,6 @@ var noSignaturePolicy string = `{"default":[{"type":"insecureAcceptAnything"}]}`
// pull `imageInput` from a container registry to `sourcePath`. // pull `imageInput` from a container registry to `sourcePath`.
func pull(ctx context.Context, imageInput types.ImageReference, localDestPath *define.VMFile, options *pullOptions) error { func pull(ctx context.Context, imageInput types.ImageReference, localDestPath *define.VMFile, options *pullOptions) error {
var policy *signature.Policy
destRef, err := layout.ParseReference(localDestPath.GetPath()) destRef, err := layout.ParseReference(localDestPath.GetPath())
if err != nil { if err != nil {
return err return err
@@ -59,21 +58,13 @@ func pull(ctx context.Context, imageInput types.ImageReference, localDestPath *d
return err return err
} }
// Policy paths returns a slice of directories where the policy.json policy, err := signature.DefaultPolicy(sysCtx)
// may live. Iterate those directories and try to see if any are if err != nil {
// valid ignoring when the file does not exist if !errors.Is(err, configfile.ErrConfigFileNotFound) {
for _, path := range policyPaths() {
policy, err = signature.NewPolicyFromFile(path)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
continue
}
return fmt.Errorf("reading signature policy: %w", err) return fmt.Errorf("reading signature policy: %w", err)
} }
}
// If no policy has been found yet, we use a no signature policy automatically // If no policy has been found yet, we use a no signature policy automatically
if policy == nil {
logrus.Debug("no signature policy file found: using default allow everything signature policy") logrus.Debug("no signature policy file found: using default allow everything signature policy")
policy, err = signature.NewPolicyFromBytes([]byte(noSignaturePolicy)) policy, err = signature.NewPolicyFromBytes([]byte(noSignaturePolicy))
if err != nil { if err != nil {
-27
View File
@@ -7,17 +7,12 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/fs"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"strings" "strings"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"go.podman.io/common/pkg/config"
"go.podman.io/image/v5/types"
"go.podman.io/storage/pkg/fileutils" "go.podman.io/storage/pkg/fileutils"
"go.podman.io/storage/pkg/homedir"
) )
// policyContent is the overall structure of a policy.json file (= c/image/v5/signature.Policy) // policyContent is the overall structure of a policy.json file (= c/image/v5/signature.Policy)
@@ -55,28 +50,6 @@ type genericTransportsContent map[string]genericRepoMap
// genericRepoMap maps a scope name to requirements that apply to that scope (= c/image/v5/signature.PolicyTransportScopes) // genericRepoMap maps a scope name to requirements that apply to that scope (= c/image/v5/signature.PolicyTransportScopes)
type genericRepoMap map[string]json.RawMessage type genericRepoMap map[string]json.RawMessage
// DefaultPolicyPath returns a path to the default policy of the system.
func DefaultPolicyPath(sys *types.SystemContext) string {
if sys != nil && sys.SignaturePolicyPath != "" {
return sys.SignaturePolicyPath
}
userPolicyFilePath := filepath.Join(homedir.Get(), filepath.FromSlash(".config/containers/policy.json"))
err := fileutils.Exists(userPolicyFilePath)
if err == nil {
return userPolicyFilePath
}
if !errors.Is(err, fs.ErrNotExist) {
logrus.Warnf("Error trying to read local config file: %s", err.Error())
}
systemDefaultPolicyPath := config.DefaultSignaturePolicyPath
if sys != nil && sys.RootForImplicitAbsolutePaths != "" {
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath)
}
return systemDefaultPolicyPath
}
// gpgIDReader returns GPG key IDs of keys stored at the provided path. // gpgIDReader returns GPG key IDs of keys stored at the provided path.
// It exists only for tests, production code should always use getGPGIdFromKeyPath. // It exists only for tests, production code should always use getGPGIdFromKeyPath.
type gpgIDReader func(string) []string type gpgIDReader func(string) []string
+4 -4
View File
@@ -19,7 +19,7 @@ var _ = Describe("Podman trust", Ordered, func() {
}) })
It("podman image trust show", func() { It("podman image trust show", func() {
session := podmanTest.Podman([]string{"image", "trust", "show", "-n", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json")}) session := podmanTest.Podman([]string{"image", "trust", "show", "-n", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--signature-policy", filepath.Join(INTEGRATION_ROOT, "test/policy.json")})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
outArray := session.OutputToStringArray() outArray := session.OutputToStringArray()
@@ -34,7 +34,7 @@ var _ = Describe("Podman trust", Ordered, func() {
It("podman image trust set", func() { It("podman image trust set", func() {
policyJSON := filepath.Join(podmanTest.TempDir, "trust_set_test.json") policyJSON := filepath.Join(podmanTest.TempDir, "trust_set_test.json")
session := podmanTest.Podman([]string{"image", "trust", "set", "--policypath", policyJSON, "-t", "accept", "default"}) session := podmanTest.Podman([]string{"image", "trust", "set", "--signature-policy", policyJSON, "-t", "accept", "default"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
var teststruct map[string][]map[string]string var teststruct map[string][]map[string]string
@@ -50,7 +50,7 @@ var _ = Describe("Podman trust", Ordered, func() {
}) })
It("podman image trust show --json", func() { It("podman image trust show --json", func() {
session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--json"}) session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--signature-policy", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--json"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(BeValidJSON()) Expect(session.OutputToString()).To(BeValidJSON())
@@ -89,7 +89,7 @@ var _ = Describe("Podman trust", Ordered, func() {
}) })
It("podman image trust show --raw", func() { It("podman image trust show --raw", func() {
session := podmanTest.Podman([]string{"image", "trust", "show", "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--raw"}) session := podmanTest.Podman([]string{"image", "trust", "show", "--signature-policy", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--raw"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
contents, err := os.ReadFile(filepath.Join(INTEGRATION_ROOT, "test/policy.json")) contents, err := os.ReadFile(filepath.Join(INTEGRATION_ROOT, "test/policy.json"))
+11 -11
View File
@@ -8,37 +8,37 @@ load helpers
@test "podman image trust set" { @test "podman image trust set" {
skip_if_remote "trust only works locally" skip_if_remote "trust only works locally"
policypath=$PODMAN_TMPDIR/policy.json policypath=$PODMAN_TMPDIR/policy.json
run_podman 125 image trust set --policypath=$policypath --type=bogus default run_podman 125 image trust set --signature-policy=$policypath --type=bogus default
is "$output" "Error: invalid choice: bogus.*" "error from --type=bogus" is "$output" "Error: invalid choice: bogus.*" "error from --type=bogus"
run_podman image trust set --policypath=$policypath --type=accept default run_podman image trust set --signature-policy=$policypath --type=accept default
run_podman image trust show --policypath=$policypath run_podman image trust show --signature-policy=$policypath
is "$output" ".*all *default *accept" "default policy should be accept" is "$output" ".*all *default *accept" "default policy should be accept"
run_podman image trust set --policypath=$policypath --type=reject default run_podman image trust set --signature-policy=$policypath --type=reject default
run_podman image trust show --policypath=$policypath run_podman image trust show --signature-policy=$policypath
is "$output" ".*all *default *reject" "default policy should be reject" is "$output" ".*all *default *reject" "default policy should be reject"
run_podman image trust set --policypath=$policypath --type=reject docker.io run_podman image trust set --signature-policy=$policypath --type=reject docker.io
run_podman image trust show --policypath=$policypath run_podman image trust show --signature-policy=$policypath
is "$output" ".*all *default *reject" "default policy should still be reject" is "$output" ".*all *default *reject" "default policy should still be reject"
is "$output" ".*repository *docker.io *reject" "docker.io should also be reject" is "$output" ".*repository *docker.io *reject" "docker.io should also be reject"
run_podman image trust show --policypath=$policypath --json run_podman image trust show --signature-policy=$policypath --json
subset=$(jq -r '.[0] | .repo_name, .type' <<<"$output" | fmt) subset=$(jq -r '.[0] | .repo_name, .type' <<<"$output" | fmt)
is "$subset" "default reject" "--json also shows default" is "$subset" "default reject" "--json also shows default"
subset=$(jq -r '.[1] | .repo_name, .type' <<<"$output" | fmt) subset=$(jq -r '.[1] | .repo_name, .type' <<<"$output" | fmt)
is "$subset" "docker.io reject" "--json also shows docker.io" is "$subset" "docker.io reject" "--json also shows docker.io"
run_podman image trust set --policypath=$policypath --type=accept docker.io run_podman image trust set --signature-policy=$policypath --type=accept docker.io
run_podman image trust show --policypath=$policypath --json run_podman image trust show --signature-policy=$policypath --json
subset=$(jq -r '.[0] | .repo_name, .type' <<<"$output" | fmt) subset=$(jq -r '.[0] | .repo_name, .type' <<<"$output" | fmt)
is "$subset" "default reject" "--json, default is still reject" is "$subset" "default reject" "--json, default is still reject"
subset=$(jq -r '.[1] | .repo_name, .type' <<<"$output" | fmt) subset=$(jq -r '.[1] | .repo_name, .type' <<<"$output" | fmt)
is "$subset" "docker.io accept" "--json, docker.io should now be accept" is "$subset" "docker.io accept" "--json, docker.io should now be accept"
policy="$(< $policypath)" policy="$(< $policypath)"
run_podman image trust show --policypath=$policypath --raw run_podman image trust show --signature-policy=$policypath --raw
is "$output" "$policy" "output should show match content of policy.json" is "$output" "$policy" "output should show match content of policy.json"
} }
-5
View File
@@ -488,11 +488,6 @@ type EngineConfig struct {
// backwards compat with older version of libpod and Podman. // backwards compat with older version of libpod and Podman.
SetOptions SetOptions
// SignaturePolicyPath is the path to a signature policy to use for
// validating images. If left empty, the containers/image default signature
// policy will be used.
SignaturePolicyPath string `toml:"-"`
// SDNotify tells container engine to allow containers to notify the host systemd of // SDNotify tells container engine to allow containers to notify the host systemd of
// readiness using the SD_NOTIFY mechanism. // readiness using the SD_NOTIFY mechanism.
SDNotify bool `toml:"-"` SDNotify bool `toml:"-"`
-6
View File
@@ -2,12 +2,6 @@
package config package config
const (
// DefaultSignaturePolicyPath is the default value for the
// policy.json file.
DefaultSignaturePolicyPath = "/usr/local/etc/containers/policy.json"
)
var defaultHelperBinariesDir = []string{ var defaultHelperBinariesDir = []string{
"/usr/local/bin", "/usr/local/bin",
"/usr/local/libexec/podman", "/usr/local/libexec/podman",
-6
View File
@@ -1,11 +1,5 @@
package config package config
const (
// DefaultSignaturePolicyPath is the default value for the
// policy.json file.
DefaultSignaturePolicyPath = "/etc/containers/policy.json"
)
var defaultHelperBinariesDir = []string{ var defaultHelperBinariesDir = []string{
// Relative to the binary directory // Relative to the binary directory
"$BINDIR/../libexec/podman", "$BINDIR/../libexec/podman",
-6
View File
@@ -5,12 +5,6 @@ import (
"go.podman.io/common/pkg/capabilities" "go.podman.io/common/pkg/capabilities"
) )
const (
// DefaultSignaturePolicyPath is the default value for the
// policy.json file.
DefaultSignaturePolicyPath = "/etc/containers/policy.json"
)
func selinuxEnabled() bool { func selinuxEnabled() bool {
return selinux.GetEnabled() return selinux.GetEnabled()
} }
-4
View File
@@ -7,10 +7,6 @@ import (
) )
const ( const (
// DefaultSignaturePolicyPath is the default value for the
// policy.json file.
DefaultSignaturePolicyPath = "/etc/containers/policy.json"
// Mount type for mounting host dir // Mount type for mounting host dir
_typeBind = "bind" _typeBind = "bind"
) )
-21
View File
@@ -15,7 +15,6 @@ import (
nettypes "go.podman.io/common/libnetwork/types" nettypes "go.podman.io/common/libnetwork/types"
"go.podman.io/common/pkg/apparmor" "go.podman.io/common/pkg/apparmor"
"go.podman.io/storage/pkg/configfile" "go.podman.io/storage/pkg/configfile"
"go.podman.io/storage/pkg/fileutils"
"go.podman.io/storage/pkg/homedir" "go.podman.io/storage/pkg/homedir"
"go.podman.io/storage/pkg/unshare" "go.podman.io/storage/pkg/unshare"
"go.podman.io/storage/types" "go.podman.io/storage/types"
@@ -177,9 +176,6 @@ const (
// DefaultSubnet is the subnet that will be used for the default // DefaultSubnet is the subnet that will be used for the default
// network. // network.
DefaultSubnet = "10.88.0.0/16" DefaultSubnet = "10.88.0.0/16"
// DefaultRootlessSignaturePolicyPath is the location within
// XDG_CONFIG_HOME of the rootless policy.json file.
DefaultRootlessSignaturePolicyPath = "containers/policy.json"
// DefaultShmSize is the default upper limit on the size of tmpfs mounts. // DefaultShmSize is the default upper limit on the size of tmpfs mounts.
DefaultShmSize = "65536k" DefaultShmSize = "65536k"
// DefaultUserNSSize indicates the default number of UIDs allocated for user namespace within a container. // DefaultUserNSSize indicates the default number of UIDs allocated for user namespace within a container.
@@ -205,23 +201,6 @@ func defaultConfig() (*Config, error) {
return nil, err return nil, err
} }
defaultEngineConfig.SignaturePolicyPath = DefaultSignaturePolicyPath
// NOTE: For now we want Windows to use system locations.
// GetRootlessUID == -1 on Windows, so exclude negative range
if unshare.GetRootlessUID() > 0 {
configHome, err := homedir.GetConfigHome()
if err != nil {
return nil, err
}
sigPath := filepath.Join(configHome, DefaultRootlessSignaturePolicyPath)
defaultEngineConfig.SignaturePolicyPath = sigPath
if err := fileutils.Exists(sigPath); err != nil {
if err := fileutils.Exists(DefaultSignaturePolicyPath); err == nil {
defaultEngineConfig.SignaturePolicyPath = DefaultSignaturePolicyPath
}
}
}
return &Config{ return &Config{
Containers: ContainersConfig{ Containers: ContainersConfig{
Annotations: configfile.Slice{}, Annotations: configfile.Slice{},
+36 -39
View File
@@ -17,26 +17,17 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"os" "os"
"path/filepath"
"go.podman.io/image/v5/docker/reference" "go.podman.io/image/v5/docker/reference"
"go.podman.io/image/v5/signature/internal" "go.podman.io/image/v5/signature/internal"
"go.podman.io/image/v5/transports" "go.podman.io/image/v5/transports"
"go.podman.io/image/v5/types" "go.podman.io/image/v5/types"
"go.podman.io/storage/pkg/fileutils" "go.podman.io/storage/pkg/configfile"
"go.podman.io/storage/pkg/homedir"
"go.podman.io/storage/pkg/regexp" "go.podman.io/storage/pkg/regexp"
) )
// systemDefaultPolicyPath is the policy path used for DefaultPolicy().
// You can override this at build time with
// -ldflags '-X go.podman.io/image/v5/signature.systemDefaultPolicyPath=$your_path'
var systemDefaultPolicyPath = builtinDefaultPolicyPath
// userPolicyFile is the path to the per user policy path.
var userPolicyFile = filepath.FromSlash(".config/containers/policy.json")
// InvalidPolicyFormatError is returned when parsing an invalid policy configuration. // InvalidPolicyFormatError is returned when parsing an invalid policy configuration.
type InvalidPolicyFormatError string type InvalidPolicyFormatError string
@@ -51,39 +42,45 @@ func (err InvalidPolicyFormatError) Error() string {
// NOTE: When this function returns an error, report it to the user and abort. // NOTE: When this function returns an error, report it to the user and abort.
// DO NOT hard-code fallback policies in your application. // DO NOT hard-code fallback policies in your application.
func DefaultPolicy(sys *types.SystemContext) (*Policy, error) { func DefaultPolicy(sys *types.SystemContext) (*Policy, error) {
policyPath, err := defaultPolicyPath(sys)
if err != nil {
return nil, err
}
return NewPolicyFromFile(policyPath)
}
// defaultPolicyPath returns a path to the relevant policy of the system, or an error if the policy is missing.
func defaultPolicyPath(sys *types.SystemContext) (string, error) {
policyFilePath, err := defaultPolicyPathWithHomeDir(sys, homedir.Get(), systemDefaultPolicyPath)
if err != nil {
return "", err
}
return policyFilePath, nil
}
// defaultPolicyPathWithHomeDir is an internal implementation detail of defaultPolicyPath,
// it exists only to allow testing it with artificial paths.
func defaultPolicyPathWithHomeDir(sys *types.SystemContext, homeDir string, systemPolicyPath string) (string, error) {
if sys != nil && sys.SignaturePolicyPath != "" { if sys != nil && sys.SignaturePolicyPath != "" {
return sys.SignaturePolicyPath, nil return NewPolicyFromFile(sys.SignaturePolicyPath)
} }
userPolicyFilePath := filepath.Join(homeDir, userPolicyFile)
if err := fileutils.Exists(userPolicyFilePath); err == nil { var rootForImplicitAbsPaths string
return userPolicyFilePath, nil if sys != nil {
rootForImplicitAbsPaths = sys.RootForImplicitAbsolutePaths
} }
if sys != nil && sys.RootForImplicitAbsolutePaths != "" {
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemPolicyPath), nil policyFiles := configfile.File{
Name: "policy",
Extension: "json",
DoNotLoadDropInFiles: true,
EnvironmentName: "CONTAINERS_POLICY_JSON",
RootForImplicitAbsolutePaths: rootForImplicitAbsPaths,
ErrorIfNotFound: true,
} }
if err := fileutils.Exists(systemPolicyPath); err == nil {
return systemPolicyPath, nil var policy *Policy
for item, err := range configfile.Read(&policyFiles) {
if err != nil {
return nil, err
}
if policy != nil {
// Coverage: This should never happen, configfile.Read ensures at most one policy file.
return nil, fmt.Errorf("internal error: expected at most one policy file, got another item %q", item.Name)
}
contents, err := io.ReadAll(item.Reader)
if err != nil {
return nil, err
}
policy, err = NewPolicyFromBytes(contents)
if err != nil {
return nil, fmt.Errorf("invalid policy in %q: %w", item.Name, err)
}
} }
return "", fmt.Errorf("no policy.json file found at any of the following: %q, %q", userPolicyFilePath, systemPolicyPath)
return policy, nil
} }
// NewPolicyFromFile returns a policy configured in the specified file. // NewPolicyFromFile returns a policy configured in the specified file.
-7
View File
@@ -1,7 +0,0 @@
//go:build !freebsd
package signature
// builtinDefaultPolicyPath is the policy path used for DefaultPolicy().
// DO NOT change this, instead see systemDefaultPolicyPath above.
const builtinDefaultPolicyPath = "/etc/containers/policy.json"
-7
View File
@@ -1,7 +0,0 @@
//go:build freebsd
package signature
// builtinDefaultPolicyPath is the policy path used for DefaultPolicy().
// DO NOT change this, instead see systemDefaultPolicyPath above.
const builtinDefaultPolicyPath = "/usr/local/etc/containers/policy.json"
+32 -3
View File
@@ -31,6 +31,10 @@ var (
// This can be overridden at build time with the following go linker flag: // This can be overridden at build time with the following go linker flag:
// -ldflags '-X go.podman.io/storage/pkg/configfile.adminOverrideConfigPath=$your_path' // -ldflags '-X go.podman.io/storage/pkg/configfile.adminOverrideConfigPath=$your_path'
adminOverrideConfigPath = getAdminOverrideConfigPath() adminOverrideConfigPath = getAdminOverrideConfigPath()
// ErrConfigFileNotFound is returned when ErrorIfNotFound is true and no config
// file could be loaded.
ErrConfigFileNotFound = errors.New("config file not found")
) )
type File struct { type File struct {
@@ -43,6 +47,8 @@ type File struct {
Extension string Extension string
// EnvironmentName is the name of environment variable that can be set to specify the override. // EnvironmentName is the name of environment variable that can be set to specify the override.
// If EnvironmentName is set, the variable with _OVERRIDE suffix is also checked for an override
// unless DoNotLoadDropInFiles is set.
// Optional. // Optional.
EnvironmentName string EnvironmentName string
@@ -55,6 +61,7 @@ type File struct {
DoNotLoadMainFiles bool DoNotLoadMainFiles bool
// DoNotLoadDropInFiles should be set if only the main files should be loaded. // DoNotLoadDropInFiles should be set if only the main files should be loaded.
// If DoNotLoadDropInFiles is set, the _OVERRIDE environment variable is ignored.
DoNotLoadDropInFiles bool DoNotLoadDropInFiles bool
// DoNotUseExtensionForConfigName makes it so that the extension is only consulted for the drop in // DoNotUseExtensionForConfigName makes it so that the extension is only consulted for the drop in
@@ -70,6 +77,9 @@ type File struct {
// For compatibility reasons this field is written to with the fully resolved paths // For compatibility reasons this field is written to with the fully resolved paths
// of each module as this is what podman expects today. // of each module as this is what podman expects today.
Modules []string Modules []string
// ErrorIfNotFound is true if an error should be returned if no file is found.
ErrorIfNotFound bool
} }
// Item is a single config file that is being read once at a time and returned by the iterator from [Read]. // Item is a single config file that is being read once at a time and returned by the iterator from [Read].
@@ -113,10 +123,14 @@ func Read(conf *File) iter.Seq2[*Item, error] {
} }
return func(yield func(*Item, error) bool) { return func(yield func(*Item, error) bool) {
usedPaths := make([]string, 0, 8)
foundAny := false
shouldLoadMainFile := !conf.DoNotLoadMainFiles shouldLoadMainFile := !conf.DoNotLoadMainFiles
shouldLoadDropIns := !conf.DoNotLoadDropInFiles shouldLoadDropIns := !conf.DoNotLoadDropInFiles
yieldAndClose := func(f *os.File) bool { yieldAndClose := func(f *os.File) bool {
foundAny = true
ok := yield(&Item{ ok := yield(&Item{
Reader: f, Reader: f,
Name: f.Name(), Name: f.Name(),
@@ -134,6 +148,7 @@ func Read(conf *File) iter.Seq2[*Item, error] {
if conf.EnvironmentName != "" { if conf.EnvironmentName != "" {
if path := os.Getenv(conf.EnvironmentName); path != "" { if path := os.Getenv(conf.EnvironmentName); path != "" {
usedPaths = append(usedPaths, path)
f, err := os.Open(path) f, err := os.Open(path)
// Do not ignore ErrNotExist here, we want to hard error if users set a wrong path here. // Do not ignore ErrNotExist here, we want to hard error if users set a wrong path here.
if err != nil { if err != nil {
@@ -165,6 +180,7 @@ func Read(conf *File) iter.Seq2[*Item, error] {
if path == "" { if path == "" {
continue continue
} }
usedPaths = append(usedPaths, path)
f, err := os.Open(path) f, err := os.Open(path)
// only ignore ErrNotExist, all other errors get return to the caller via yield // only ignore ErrNotExist, all other errors get return to the caller via yield
if err != nil { if err != nil {
@@ -191,6 +207,7 @@ func Read(conf *File) iter.Seq2[*Item, error] {
return return
} }
for _, file := range files { for _, file := range files {
usedPaths = append(usedPaths, file)
f, err := os.Open(file) f, err := os.Open(file)
// only ignore ErrNotExist, all other errors get return to the caller via yield // only ignore ErrNotExist, all other errors get return to the caller via yield
if err != nil { if err != nil {
@@ -211,7 +228,7 @@ func Read(conf *File) iter.Seq2[*Item, error] {
dirs := moduleDirectories(defaultConfig, overrideConfig, userConfig) dirs := moduleDirectories(defaultConfig, overrideConfig, userConfig)
resolvedModules := make([]string, 0, len(conf.Modules)) resolvedModules := make([]string, 0, len(conf.Modules))
for _, module := range conf.Modules { for _, module := range conf.Modules {
f, err := resolveModule(module, dirs) f, err := resolveModule(module, dirs, &usedPaths)
if err != nil { if err != nil {
yield(nil, fmt.Errorf("could not resolve module: %w", err)) yield(nil, fmt.Errorf("could not resolve module: %w", err))
return return
@@ -224,9 +241,10 @@ func Read(conf *File) iter.Seq2[*Item, error] {
conf.Modules = resolvedModules conf.Modules = resolvedModules
} }
if conf.EnvironmentName != "" { if conf.EnvironmentName != "" && !conf.DoNotLoadDropInFiles {
// The _OVERRIDE env must be appended after loading all files, even modules. // The _OVERRIDE env must be appended after loading all files, even modules.
if path := os.Getenv(conf.EnvironmentName + "_OVERRIDE"); path != "" { if path := os.Getenv(conf.EnvironmentName + "_OVERRIDE"); path != "" {
usedPaths = append(usedPaths, path)
f, err := os.Open(path) f, err := os.Open(path)
// Do not ignore ErrNotExist here, we want to hard error if users set a wrong path here. // Do not ignore ErrNotExist here, we want to hard error if users set a wrong path here.
if err != nil { if err != nil {
@@ -238,6 +256,11 @@ func Read(conf *File) iter.Seq2[*Item, error] {
} }
} }
} }
if conf.ErrorIfNotFound && !foundAny {
yield(nil, fmt.Errorf("%w: no %s file found; searched paths: %q", ErrConfigFileNotFound, configFileName, usedPaths))
return
}
} }
} }
@@ -324,8 +347,11 @@ func moduleDirectories(defaultConfig, overrideConfig, userConfig string) []strin
} }
// Resolve the specified path to a module. // Resolve the specified path to a module.
func resolveModule(path string, dirs []string) (*os.File, error) { func resolveModule(path string, dirs []string, usedPaths *[]string) (*os.File, error) {
if filepath.IsAbs(path) { if filepath.IsAbs(path) {
if usedPaths != nil {
*usedPaths = append(*usedPaths, path)
}
return os.Open(path) return os.Open(path)
} }
@@ -334,6 +360,9 @@ func resolveModule(path string, dirs []string) (*os.File, error) {
var multiErr error var multiErr error
for _, d := range dirs { for _, d := range dirs {
candidate := filepath.Join(d, path) candidate := filepath.Join(d, path)
if usedPaths != nil {
*usedPaths = append(*usedPaths, candidate)
}
f, err := os.Open(candidate) f, err := os.Open(candidate)
if err == nil { if err == nil {
+3 -3
View File
@@ -733,7 +733,7 @@ go.opentelemetry.io/otel/trace
go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/embedded
go.opentelemetry.io/otel/trace/internal/telemetry go.opentelemetry.io/otel/trace/internal/telemetry
go.opentelemetry.io/otel/trace/noop go.opentelemetry.io/otel/trace/noop
# go.podman.io/common v0.67.2-0.20260416202057-7d53666cdee9 # go.podman.io/common v0.67.2-0.20260420103546-618304d6f83d
## explicit; go 1.25.6 ## explicit; go 1.25.6
go.podman.io/common/internal go.podman.io/common/internal
go.podman.io/common/libimage go.podman.io/common/libimage
@@ -799,7 +799,7 @@ go.podman.io/common/pkg/umask
go.podman.io/common/pkg/util go.podman.io/common/pkg/util
go.podman.io/common/pkg/version go.podman.io/common/pkg/version
go.podman.io/common/version go.podman.io/common/version
# go.podman.io/image/v5 v5.39.3-0.20260416202057-7d53666cdee9 # go.podman.io/image/v5 v5.39.3-0.20260420103546-618304d6f83d
## explicit; go 1.25.6 ## explicit; go 1.25.6
go.podman.io/image/v5/copy go.podman.io/image/v5/copy
go.podman.io/image/v5/directory go.podman.io/image/v5/directory
@@ -876,7 +876,7 @@ go.podman.io/image/v5/transports
go.podman.io/image/v5/transports/alltransports go.podman.io/image/v5/transports/alltransports
go.podman.io/image/v5/types go.podman.io/image/v5/types
go.podman.io/image/v5/version go.podman.io/image/v5/version
# go.podman.io/storage v1.62.1-0.20260416202057-7d53666cdee9 # go.podman.io/storage v1.62.1-0.20260420103546-618304d6f83d
## explicit; go 1.25.0 ## explicit; go 1.25.0
go.podman.io/storage go.podman.io/storage
go.podman.io/storage/drivers go.podman.io/storage/drivers