Skip to content

Commit 64cd413

Browse files
committed
policy: support reading policy from stdin via --file -
Allow passing policy content through stdin by specifying "--file -" in the eval command. This enables piping policy data without requiring a file on disk. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
1 parent 7df7b42 commit 64cd413

3 files changed

Lines changed: 77 additions & 4 deletions

File tree

commands/policy/eval.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"io"
78
"io/fs"
89
"maps"
910
"os"
@@ -191,9 +192,8 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
191192
if opts.filename == "" {
192193
return errors.New("filename is required")
193194
}
194-
policyName := opts.filename
195-
policyFile := policyName + ".rego"
196-
policyData, err := os.ReadFile(policyFile)
195+
policyName, policyFile := policyFileNames(opts.filename)
196+
policyData, err := readPolicyData(policyFile, os.Stdin)
197197
if err != nil {
198198
return errors.Wrapf(err, "failed to read policy file %s", policyFile)
199199
}
@@ -267,6 +267,20 @@ func runEval(ctx context.Context, dockerCli command.Cli, source string, opts eva
267267
}
268268
}
269269

270+
func policyFileNames(filename string) (string, string) {
271+
if filename == "-" {
272+
return "stdin", filename
273+
}
274+
return filename, filename + ".rego"
275+
}
276+
277+
func readPolicyData(filename string, stdin io.Reader) ([]byte, error) {
278+
if filename == "-" {
279+
return io.ReadAll(stdin)
280+
}
281+
return os.ReadFile(filename)
282+
}
283+
270284
func selectReloadFields(fields []string, unknowns []string) ([]string, []string) {
271285
if len(fields) == 0 {
272286
return nil, nil

docs/reference/buildx_policy_eval.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ Evaluate policy for a source
1010
| `--builder` | `string` | | Override the configured builder instance |
1111
| `-D`, `--debug` | `bool` | | Enable debug logging |
1212
| `--fields` | `stringSlice` | | Fields to evaluate |
13-
| `--filename` | `string` | `Dockerfile` | Policy filename to evaluate |
13+
| `-f`, `--file` | `string` | `Dockerfile` | Policy filename to evaluate |
14+
| `--platform` | `string` | | Target platform for policy evaluation |
1415
| `--print` | `bool` | | Print policy output |
1516

1617

tests/policy_eval.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
var policyEvalTests = []func(t *testing.T, sb integration.Sandbox){
2222
testPolicyEvalAllow,
2323
testPolicyEvalDeny,
24+
testPolicyEvalStdinFile,
2425
testPolicyEvalPrint,
2526
testPolicyEvalFields,
2627
testPolicyEvalLabel,
@@ -88,6 +89,63 @@ decision := {"allow": allow}
8889
require.Contains(t, string(out), "policy denied")
8990
}
9091

92+
func testPolicyEvalStdinFile(t *testing.T, sb integration.Sandbox) {
93+
skipNoCompatBuildKit(t, sb, ">= 0.26.0-0", "policy input requires BuildKit v0.26.0+")
94+
testCases := []struct {
95+
name string
96+
policy string
97+
wantErrContains string
98+
}{
99+
{
100+
name: "allow",
101+
policy: `
102+
package docker
103+
104+
default allow = false
105+
106+
allow if not input.image
107+
108+
allow if input.image.repo == "busybox"
109+
110+
decision := {"allow": allow}
111+
`,
112+
},
113+
{
114+
name: "deny",
115+
policy: `
116+
package docker
117+
118+
default allow = false
119+
120+
allow if input.image.repo == "alpine"
121+
122+
decision := {"allow": allow}
123+
`,
124+
wantErrContains: "policy denied",
125+
},
126+
}
127+
128+
for _, tc := range testCases {
129+
t.Run(tc.name, func(t *testing.T) {
130+
cmd := buildxCmd(sb, withArgs(
131+
"policy",
132+
"eval",
133+
"--file",
134+
"-",
135+
"docker-image://busybox:latest",
136+
))
137+
cmd.Stdin = strings.NewReader(tc.policy)
138+
out, err := cmd.CombinedOutput()
139+
if tc.wantErrContains == "" {
140+
require.NoError(t, err, string(out))
141+
return
142+
}
143+
require.Error(t, err, string(out))
144+
require.Contains(t, string(out), tc.wantErrContains)
145+
})
146+
}
147+
}
148+
91149
func testPolicyEvalPrint(t *testing.T, sb integration.Sandbox) {
92150
skipNoCompatBuildKit(t, sb, ">= 0.26.0-0", "policy input requires BuildKit v0.26.0+")
93151
cmd := buildxCmd(sb, withArgs(

0 commit comments

Comments
 (0)