Repository: vmware/tern
Pull request #580 (2020-03-12 13:27:09)

Parsing ARG varibales
Replace the arg varibles in the dockerfile if known.

Work towards #508.

Signed-off-by: WangJL <hazard15020@gmail.com>

nishakm: @ForgetMe17 could you update your commit message?
```
Parsing ARG varibales --> variables

Replace the arg varibles --> variables in the dockerfile if known.

Work towards #508.
ForgetMe17: Thanks for your review. Sorry for the misspelling, i will be more careful.
nishakm: @ForgetMe17 no worries! You're doing great! One request I would like to make is to add more description about what you did to resolve the issue in the commit message. It's a significant change and a lot of work :)
nishakm: @rnjudge OK to merge?
rnjudge: > @rnjudge OK to merge?

LGTM!

Patch:
diff --git a/tern/analyze/docker/dockerfile.py b/tern/analyze/docker/dockerfile.py
index a1f7d32..39469e2 100644
--- a/tern/analyze/docker/dockerfile.py
+++ b/tern/analyze/docker/dockerfile.py
@@ -112,6 +112,25 @@ def expand_vars(dfobj):
             replace_env(dfobj.prev_env, obj)
 
 
+def expand_arg(dfobj):
+    '''Replace the ARG variables with their values if known
+    dfobj: the Dockerfile object created using get_dockerfile_obj'''
+    # get arg dictionary
+    arg_dict = {}
+    for instruction_desc in dfobj.structure:
+        if instruction_desc['instruction'] == 'ARG':
+            instruction_value_split = instruction_desc['value'].split('=')
+            # contains '='
+            if len(instruction_value_split) == 2:
+                key = instruction_value_split[0].strip(' ')
+                value = instruction_value_split[1].strip(' ')
+                arg_dict[key] = value
+    # expand arg variables
+    if arg_dict:
+        for obj in dfobj.structure:
+            replace_env(arg_dict, obj)
+
+
 def parse_from_image(dfobj):
     '''Get a list of dictionaries from the FROM instruction. The dictionary
     should be of the form:


Test patch:
diff --git a/tests/dockerfiles/buildpack_deps_jessie_arg b/tests/dockerfiles/buildpack_deps_jessie_arg
new file mode 100644
index 0000000..3b297d6
--- /dev/null
+++ b/tests/dockerfiles/buildpack_deps_jessie_arg
@@ -0,0 +1,19 @@
+ARG version=jessie
+FROM debian:${version}
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+		ca-certificates \
+		curl \
+		netbase \
+		wget \
+	&& rm -rf /var/lib/apt/lists/*
+
+RUN set -ex; \
+	if ! command -v gpg > /dev/null; then \
+		apt-get update; \
+		apt-get install -y --no-install-recommends \
+			gnupg \
+			dirmngr \
+		; \
+		rm -rf /var/lib/apt/lists/*; \
+	fi
diff --git a/tests/test_analyze_docker_dockerfile.py b/tests/test_analyze_docker_dockerfile.py
index da91048..f155c33 100644
--- a/tests/test_analyze_docker_dockerfile.py
+++ b/tests/test_analyze_docker_dockerfile.py
@@ -14,10 +14,12 @@ class TestAnalyzeDockerDockerfile(unittest.TestCase):
         self.buildpack = 'tests/dockerfiles/buildpack_deps_jessie_curl'
         self.buildpackpinned = 'tests/dockerfiles/buildpack_deps_jessie_pinned'
         self.golang = 'tests/dockerfiles/golang_1.13_stretch'
+        self.buildpackarg = 'tests/dockerfiles/buildpack_deps_jessie_arg'
 
     def tearDown(self):
         del self.buildpack
         del self.golang
+        del self.buildpackarg
 
     def testDockerfileObject(self):
         dfobj = dockerfile.Dockerfile()
@@ -102,6 +104,15 @@ class TestAnalyzeDockerDockerfile(unittest.TestCase):
                                        'digest_type': 'sha256',
                                        'digest': debian_digest}])
 
+    def testExpandArg(self):
+        dfobj = dockerfile.get_dockerfile_obj(self.buildpackarg)
+        dockerfile.expand_arg(dfobj)
+        replace_content = 'FROM debian:jessie\n'
+        replace_value = 'debian:jessie'
+        struct = dfobj.structure[1]
+        self.assertEqual(struct['value'], replace_value)
+        self.assertEqual(struct['content'], replace_content)
+
 
 if __name__ == '__main__':
     unittest.main()