Browse code

forbid chained onbuild, from & maintainer triggers

This changes the way onbuild works:
- forbids the chaining of onbuild instructions
- forbids the use of `onbuild from`
- forbids the use of `onbuild maintainer`

It also makes docker throw errors when encountering such triggers when
executing the triggers during `FROM`.

Three tests have been added:
- ensure that chained onbuild (`onbuild onbuild`) is forbidden
- ensure that `onbuild from` is forbidden
- ensure that `onbuild maintainer` is forbidden

Docker-DCO-1.1-Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> (github: unclejack)

unclejack authored on 2014/02/21 00:16:45
Showing 3 changed files
... ...
@@ -117,6 +117,14 @@ func (b *buildFile) CmdFrom(name string) error {
117 117
 		fmt.Fprintf(b.errStream, "# Executing %d build triggers\n", nTriggers)
118 118
 	}
119 119
 	for n, step := range b.config.OnBuild {
120
+		splitStep := strings.Split(step, " ")
121
+		stepInstruction := strings.ToUpper(strings.Trim(splitStep[0], " "))
122
+		switch stepInstruction {
123
+		case "ONBUILD":
124
+			return fmt.Errorf("Source image contains forbidden chained `ONBUILD ONBUILD` trigger: %s", step)
125
+		case "MAINTAINER", "FROM":
126
+			return fmt.Errorf("Source image contains forbidden %s trigger: %s", stepInstruction, step)
127
+		}
120 128
 		if err := b.BuildStep(fmt.Sprintf("onbuild-%d", n), step); err != nil {
121 129
 			return err
122 130
 		}
... ...
@@ -128,6 +136,14 @@ func (b *buildFile) CmdFrom(name string) error {
128 128
 // The ONBUILD command declares a build instruction to be executed in any future build
129 129
 // using the current image as a base.
130 130
 func (b *buildFile) CmdOnbuild(trigger string) error {
131
+	splitTrigger := strings.Split(trigger, " ")
132
+	triggerInstruction := strings.ToUpper(strings.Trim(splitTrigger[0], " "))
133
+	switch triggerInstruction {
134
+	case "ONBUILD":
135
+		return fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
136
+	case "MAINTAINER", "FROM":
137
+		return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", triggerInstruction)
138
+	}
131 139
 	b.config.OnBuild = append(b.config.OnBuild, trigger)
132 140
 	return b.commit("", b.config.Cmd, fmt.Sprintf("ONBUILD %s", trigger))
133 141
 }
... ...
@@ -466,6 +466,8 @@ For example you might add something like this:
466 466
     ONBUILD RUN /usr/local/bin/python-build --dir /app/src
467 467
     [...]
468 468
 
469
+.. warning:: Chaining ONBUILD instructions using `ONBUILD ONBUILD` isn't allowed.
470
+.. warning:: ONBUILD may not trigger FROM or MAINTAINER instructions.
469 471
 
470 472
 .. _dockerfile_examples:
471 473
 
... ...
@@ -924,3 +924,45 @@ func TestBuildOnBuildTrigger(t *testing.T) {
924 924
 	}
925 925
 	// FIXME: test that the 'foobar' file was created in the final build.
926 926
 }
927
+
928
+func TestBuildOnBuildForbiddenChainedTrigger(t *testing.T) {
929
+	_, err := buildImage(testContextTemplate{`
930
+	from {IMAGE}
931
+	onbuild onbuild run echo test
932
+	`,
933
+		nil, nil,
934
+	},
935
+		t, nil, true,
936
+	)
937
+	if err == nil {
938
+		t.Fatal("Error should not be nil")
939
+	}
940
+}
941
+
942
+func TestBuildOnBuildForbiddenFromTrigger(t *testing.T) {
943
+	_, err := buildImage(testContextTemplate{`
944
+	from {IMAGE}
945
+	onbuild from {IMAGE}
946
+	`,
947
+		nil, nil,
948
+	},
949
+		t, nil, true,
950
+	)
951
+	if err == nil {
952
+		t.Fatal("Error should not be nil")
953
+	}
954
+}
955
+
956
+func TestBuildOnBuildForbiddenMaintainerTrigger(t *testing.T) {
957
+	_, err := buildImage(testContextTemplate{`
958
+	from {IMAGE}
959
+	onbuild maintainer test
960
+	`,
961
+		nil, nil,
962
+	},
963
+		t, nil, true,
964
+	)
965
+	if err == nil {
966
+		t.Fatal("Error should not be nil")
967
+	}
968
+}