launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25519
[Merge] ~pappacena/launchpad-buildd:security-manifest into launchpad-buildd:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad-buildd:security-manifest into launchpad-buildd:master.
Commit message:
Including manifest file in resulting OCI image.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pappacena/launchpad-buildd/+git/launchpad-buildd/+merge/392400
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad-buildd:security-manifest into launchpad-buildd:master.
diff --git a/lpbuildd/target/build_oci.py b/lpbuildd/target/build_oci.py
index af56671..448bbdb 100644
--- a/lpbuildd/target/build_oci.py
+++ b/lpbuildd/target/build_oci.py
@@ -6,6 +6,7 @@ from __future__ import print_function
__metaclass__ = type
from collections import OrderedDict
+import json
import logging
import os.path
import sys
@@ -53,6 +54,7 @@ class BuildOCI(SnapBuildProxyOperationMixin, VCSOperationMixin,
super(BuildOCI, self).__init__(args, parser)
self.bin = os.path.dirname(sys.argv[0])
self.buildd_path = os.path.join("/home/buildd", self.args.name)
+ self.security_manifest_target_path = "/usr/share/rocks/manifest.json"
def _add_docker_engine_proxy_settings(self):
"""Add systemd file for docker proxy settings."""
@@ -119,6 +121,56 @@ class BuildOCI(SnapBuildProxyOperationMixin, VCSOperationMixin,
env = self.build_proxy_environment(proxy_url=self.args.proxy_url)
self.vcs_fetch(self.args.name, cwd="/home/buildd", env=env)
+ def createSecurityManifest(self):
+ """Generates the security manifest file, returning the tmp file name
+ where it is stored in the backend.
+ """
+ content = {
+ "manifest-version": "1"
+ }
+ local_filename = tempfile.mktemp()
+ destination = "/tmp/security-manifest.json"
+ with open(local_filename, 'w') as fd:
+ json.dump(content, fd, indent=2)
+ self.backend.copy_in(local_filename, destination)
+ return destination
+
+ def startImageContainer(self):
+ """Starts a container from the built image without actually running
+ the image's command."""
+ self.run_build_command([
+ "docker", "run", "-d", "--name", self.args.name, self.args.name,
+ "sleep", "infinity"])
+
+ def stopImageContainer(self):
+ self.run_build_command(["docker", "stop", self.args.name])
+
+ def removeImageContainer(self):
+ self.run_build_command(["docker", "rm", self.args.name])
+
+ def commitImage(self):
+ """Commits the tmp container, overriding the originally built image."""
+ self.run_build_command([
+ "docker", "commit", self.args.name, self.args.name])
+
+ def addFileToImageContainer(self, src, dst):
+ """Copy a file in the local filesystem into the image container."""
+ dir_path = os.path.dirname(dst)
+ # Ensure the destination directory exists.
+ self.run_build_command(
+ ["docker", "exec", self.args.name, "mkdir", "-p", dir_path])
+ self.run_build_command(
+ ["docker", "cp", src, "%s:%s" % (self.args.name, dst)])
+
+ def addSecurityManifest(self):
+ self.startImageContainer()
+ manifest_filename = self.createSecurityManifest()
+ self.addFileToImageContainer(
+ manifest_filename, self.security_manifest_target_path)
+ self.stopImageContainer()
+ self.commitImage()
+ self.removeImageContainer()
+
def build(self):
logger.info("Running build phase...")
args = ["docker", "build", "--no-cache"]
@@ -143,6 +195,7 @@ class BuildOCI(SnapBuildProxyOperationMixin, VCSOperationMixin,
self._check_path_escape(build_context_path)
args.append(build_context_path)
self.run_build_command(args)
+ self.addSecurityManifest()
def run(self):
try:
diff --git a/lpbuildd/target/tests/test_build_oci.py b/lpbuildd/target/tests/test_build_oci.py
index e58344f..106bdf2 100644
--- a/lpbuildd/target/tests/test_build_oci.py
+++ b/lpbuildd/target/tests/test_build_oci.py
@@ -290,6 +290,31 @@ class TestBuildOCI(TestCase):
cwd="/home/buildd/test-image", **env),
]))
+ def assertRanPostBuildCommands(self, build_oci):
+ self.assertThat(build_oci.backend.run.calls[1:], MatchesListwise([
+ RanBuildCommand(
+ ['docker', 'run', '-d', '--name', 'test-image', 'test-image',
+ 'sleep', 'infinity'],
+ cwd="/home/buildd/test-image"),
+ RanBuildCommand(
+ ['docker', 'exec', 'test-image', 'mkdir', '-p',
+ '/usr/share/rocks'],
+ cwd="/home/buildd/test-image"),
+ RanBuildCommand(
+ ['docker', 'cp', '/tmp/security-manifest.json',
+ 'test-image:/usr/share/rocks/manifest.json'],
+ cwd="/home/buildd/test-image"),
+ RanBuildCommand(
+ ['docker', 'stop', 'test-image'],
+ cwd="/home/buildd/test-image"),
+ RanBuildCommand(
+ ['docker', 'commit', 'test-image', 'test-image'],
+ cwd="/home/buildd/test-image"),
+ RanBuildCommand(
+ ['docker', 'rm', 'test-image'],
+ cwd="/home/buildd/test-image"),
+ ]))
+
def test_build(self):
args = [
"build-oci",
@@ -299,12 +324,11 @@ class TestBuildOCI(TestCase):
build_oci = parse_args(args=args).operation
build_oci.backend.add_dir('/build/test-directory')
build_oci.build()
- self.assertThat(build_oci.backend.run.calls, MatchesListwise([
- RanBuildCommand(
- ["docker", "build", "--no-cache", "--tag", "test-image",
- "/home/buildd/test-image/."],
- cwd="/home/buildd/test-image"),
- ]))
+ self.assertThat(build_oci.backend.run.calls[0], RanBuildCommand(
+ ["docker", "build", "--no-cache", "--tag", "test-image",
+ "/home/buildd/test-image/."],
+ cwd="/home/buildd/test-image"))
+ self.assertRanPostBuildCommands(build_oci)
def test_build_with_file(self):
args = [
@@ -316,13 +340,12 @@ class TestBuildOCI(TestCase):
build_oci = parse_args(args=args).operation
build_oci.backend.add_dir('/build/test-directory')
build_oci.build()
- self.assertThat(build_oci.backend.run.calls, MatchesListwise([
- RanBuildCommand(
- ["docker", "build", "--no-cache", "--tag", "test-image",
- "--file", "./build-aux/Dockerfile",
- "/home/buildd/test-image/."],
- cwd="/home/buildd/test-image"),
- ]))
+ self.assertThat(build_oci.backend.run.calls[0], RanBuildCommand(
+ ["docker", "build", "--no-cache", "--tag", "test-image",
+ "--file", "./build-aux/Dockerfile",
+ "/home/buildd/test-image/."],
+ cwd="/home/buildd/test-image"))
+ self.assertRanPostBuildCommands(build_oci)
def test_build_with_path(self):
args = [
@@ -334,12 +357,11 @@ class TestBuildOCI(TestCase):
build_oci = parse_args(args=args).operation
build_oci.backend.add_dir('/build/test-directory')
build_oci.build()
- self.assertThat(build_oci.backend.run.calls, MatchesListwise([
- RanBuildCommand(
- ["docker", "build", "--no-cache", "--tag", "test-image",
- "/home/buildd/test-image/a-sub-directory/"],
- cwd="/home/buildd/test-image"),
- ]))
+ self.assertThat(build_oci.backend.run.calls[0], RanBuildCommand(
+ ["docker", "build", "--no-cache", "--tag", "test-image",
+ "/home/buildd/test-image/a-sub-directory/"],
+ cwd="/home/buildd/test-image"))
+ self.assertRanPostBuildCommands(build_oci)
def test_build_with_file_and_path(self):
args = [
@@ -352,13 +374,12 @@ class TestBuildOCI(TestCase):
build_oci = parse_args(args=args).operation
build_oci.backend.add_dir('/build/test-directory')
build_oci.build()
- self.assertThat(build_oci.backend.run.calls, MatchesListwise([
- RanBuildCommand(
- ["docker", "build", "--no-cache", "--tag", "test-image",
- "--file", "test-build-path/build-aux/Dockerfile",
- "/home/buildd/test-image/test-build-path"],
- cwd="/home/buildd/test-image"),
- ]))
+ self.assertThat(build_oci.backend.run.calls[0], RanBuildCommand(
+ ["docker", "build", "--no-cache", "--tag", "test-image",
+ "--file", "test-build-path/build-aux/Dockerfile",
+ "/home/buildd/test-image/test-build-path"],
+ cwd="/home/buildd/test-image"))
+ self.assertRanPostBuildCommands(build_oci)
def test_build_with_args(self):
args = [
@@ -372,14 +393,13 @@ class TestBuildOCI(TestCase):
build_oci = parse_args(args=args).operation
build_oci.backend.add_dir('/build/test-directory')
build_oci.build()
- self.assertThat(build_oci.backend.run.calls, MatchesListwise([
- RanBuildCommand(
- ["docker", "build", "--no-cache", "--tag", "test-image",
- "--file", "test-build-path/build-aux/Dockerfile",
- "--build-arg=VAR1=xxx", "--build-arg=VAR2=yyy",
- "/home/buildd/test-image/test-build-path"],
- cwd="/home/buildd/test-image"),
- ]))
+ self.assertThat(build_oci.backend.run.calls[0], RanBuildCommand(
+ ["docker", "build", "--no-cache", "--tag", "test-image",
+ "--file", "test-build-path/build-aux/Dockerfile",
+ "--build-arg=VAR1=xxx", "--build-arg=VAR2=yyy",
+ "/home/buildd/test-image/test-build-path"],
+ cwd="/home/buildd/test-image"))
+ self.assertRanPostBuildCommands(build_oci)
def test_build_proxy(self):
args = [
@@ -391,14 +411,13 @@ class TestBuildOCI(TestCase):
build_oci = parse_args(args=args).operation
build_oci.backend.add_dir('/build/test-directory')
build_oci.build()
- self.assertThat(build_oci.backend.run.calls, MatchesListwise([
- RanBuildCommand(
- ["docker", "build", "--no-cache",
- "--build-arg", "http_proxy=http://proxy.example:3128/",
- "--build-arg", "https_proxy=http://proxy.example:3128/",
- "--tag", "test-image", "/home/buildd/test-image/."],
- cwd="/home/buildd/test-image"),
- ]))
+ self.assertThat(build_oci.backend.run.calls[0], RanBuildCommand(
+ ["docker", "build", "--no-cache",
+ "--build-arg", "http_proxy=http://proxy.example:3128/",
+ "--build-arg", "https_proxy=http://proxy.example:3128/",
+ "--tag", "test-image", "/home/buildd/test-image/."],
+ cwd="/home/buildd/test-image"))
+ self.assertRanPostBuildCommands(build_oci)
def test_run_succeeds(self):
args = [