Skip to content

Commit d8247b7

Browse files
authored
Merge branch '16-12-25' into containers-from-image
2 parents 02de77b + ab1c94e commit d8247b7

File tree

15 files changed

+826
-54
lines changed

15 files changed

+826
-54
lines changed

src/confcom/HISTORY.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
Release History
44
===============
55

6+
1.5.0
7+
++++++
8+
* restored the behaviour of --upload-fragment in acifragmentgen to attach to first image in input
9+
* added --push-fragment-to flag to acifragmentgen to allow explicit uploading of standalone fragments
10+
* added --attach-fragment-to flag to acifragmentgen to allow explicit uploading of image attached fragments
11+
612
1.4.5
713
++++++
814
* Drop the dependency on OPA

src/confcom/azext_confcom/_params.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
# pylint: disable=line-too-long
66

77
import json
8+
import argparse
9+
import sys
810
from knack.arguments import CLIArgumentType
911
from azext_confcom._validators import (
1012
validate_params_file,
@@ -44,6 +46,32 @@ def load_arguments(self, _):
4446
c.argument("tags", tags_type)
4547
c.argument("confcom_name", confcom_name_type, options_list=["--name", "-n"])
4648

49+
with self.argument_context("confcom fragment attach") as c:
50+
c.positional(
51+
"signed_fragment",
52+
nargs='?',
53+
type=argparse.FileType('rb'),
54+
default=sys.stdin.buffer,
55+
help="Signed fragment to attach",
56+
)
57+
c.argument(
58+
"manifest_tag",
59+
help="Manifest tag for the fragment",
60+
)
61+
62+
with self.argument_context("confcom fragment push") as c:
63+
c.positional(
64+
"signed_fragment",
65+
nargs='?',
66+
type=argparse.FileType('rb'),
67+
default=sys.stdin.buffer,
68+
help="Signed fragment to push",
69+
)
70+
c.argument(
71+
"manifest_tag",
72+
help="Manifest tag for the fragment",
73+
)
74+
4775
with self.argument_context("confcom acipolicygen") as c:
4876
c.argument(
4977
"input_path",
@@ -362,6 +390,13 @@ def load_arguments(self, _):
362390
type=json.loads,
363391
help='Container definitions to include in the policy'
364392
)
393+
c.argument(
394+
"out_signed_fragment",
395+
action="store_true",
396+
default=False,
397+
required=False,
398+
help="Emit only the signed fragment bytes",
399+
)
365400

366401
with self.argument_context("confcom katapolicygen") as c:
367402
c.argument(
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
import os
7+
import subprocess
8+
import tempfile
9+
from typing import BinaryIO
10+
11+
12+
def oras_attach(
13+
signed_fragment: BinaryIO,
14+
manifest_tag: str,
15+
) -> None:
16+
subprocess.run(
17+
[
18+
"oras",
19+
"attach",
20+
"--artifact-type", "application/x-ms-ccepolicy-frag",
21+
manifest_tag,
22+
os.path.relpath(signed_fragment.name, start=os.getcwd()),
23+
],
24+
check=True,
25+
timeout=120,
26+
)
27+
28+
29+
def fragment_attach(
30+
signed_fragment: BinaryIO,
31+
manifest_tag: str,
32+
) -> None:
33+
34+
if signed_fragment.name == "<stdin>":
35+
with tempfile.NamedTemporaryFile(delete=True) as temp_signed_fragment:
36+
temp_signed_fragment.write(signed_fragment.read())
37+
temp_signed_fragment.flush()
38+
oras_attach(
39+
signed_fragment=temp_signed_fragment,
40+
manifest_tag=manifest_tag,
41+
)
42+
else:
43+
oras_attach(
44+
signed_fragment=signed_fragment,
45+
manifest_tag=manifest_tag,
46+
)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
6+
import os
7+
import subprocess
8+
import tempfile
9+
from typing import BinaryIO
10+
11+
12+
def oras_push(
13+
signed_fragment: BinaryIO,
14+
manifest_tag: str,
15+
) -> None:
16+
subprocess.run(
17+
[
18+
"oras",
19+
"push",
20+
"--artifact-type", "application/x-ms-ccepolicy-frag",
21+
manifest_tag,
22+
os.path.relpath(signed_fragment.name, start=os.getcwd()),
23+
],
24+
check=True,
25+
timeout=120,
26+
)
27+
28+
29+
def fragment_push(
30+
signed_fragment: BinaryIO,
31+
manifest_tag: str,
32+
) -> None:
33+
34+
if signed_fragment.name == "<stdin>":
35+
with tempfile.NamedTemporaryFile(delete=True) as temp_signed_fragment:
36+
temp_signed_fragment.write(signed_fragment.read())
37+
temp_signed_fragment.flush()
38+
oras_push(
39+
signed_fragment=temp_signed_fragment,
40+
manifest_tag=manifest_tag,
41+
)
42+
else:
43+
oras_push(
44+
signed_fragment=signed_fragment,
45+
manifest_tag=manifest_tag,
46+
)

src/confcom/azext_confcom/commands.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ def load_command_table(self, _):
1111
g.custom_command("acifragmentgen", "acifragmentgen_confcom")
1212
g.custom_command("katapolicygen", "katapolicygen_confcom")
1313

14+
with self.command_group("confcom fragment") as g:
15+
g.custom_command("attach", "fragment_attach", is_preview=True)
16+
g.custom_command("push", "fragment_push", is_preview=True)
17+
1418
with self.command_group("confcom"):
1519
pass
1620

src/confcom/azext_confcom/custom.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ def acifragmentgen_confcom(
258258
upload_fragment: bool = False,
259259
no_print: bool = False,
260260
fragments_json: str = "",
261+
out_signed_fragment: bool = False,
261262
):
262263
if container_definitions is None:
263264
container_definitions = []
@@ -364,24 +365,39 @@ def acifragmentgen_confcom(
364365

365366
fragment_text = policy.generate_fragment(namespace, svn, output_type, omit_id=omit_id)
366367

367-
if output_type != security_policy.OutputType.DEFAULT and not no_print:
368+
if output_type != security_policy.OutputType.DEFAULT and not no_print and not out_signed_fragment:
368369
print(fragment_text)
369370

370371
# take ".rego" off the end of the filename if it's there, it'll get added back later
371372
output_filename = output_filename.replace(".rego", "")
372373
filename = f"{output_filename or namespace}.rego"
374+
375+
if out_signed_fragment:
376+
filename = os.path.join("/tmp", filename)
377+
373378
os_util.write_str_to_file(filename, fragment_text)
374379

375380
if key:
376381
cose_proxy = CoseSignToolProxy()
377382
iss = cose_proxy.create_issuer(chain)
378383
out_path = filename + ".cose"
379384

385+
if out_signed_fragment:
386+
out_path = os.path.join("/tmp", os.path.basename(out_path))
387+
380388
cose_proxy.cose_sign(filename, key, chain, feed, iss, algo, out_path)
381-
if upload_fragment and image_target:
382-
oras_proxy.attach_fragment_to_image(image_target, out_path)
383-
elif upload_fragment:
384-
oras_proxy.push_fragment_to_registry(feed, out_path)
389+
390+
# Preserve default behaviour established since version 1.1.0 of attaching
391+
# the fragment to the first image specified in input
392+
# (or --image-target if specified)
393+
if upload_fragment:
394+
oras_proxy.attach_fragment_to_image(
395+
image_name=image_target or policy_images[0].containerImage,
396+
filename=out_path,
397+
)
398+
399+
if out_signed_fragment:
400+
sys.stdout.buffer.write(open(out_path, "rb").read())
385401

386402

387403
def katapolicygen_confcom(

0 commit comments

Comments
 (0)