-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Support containers without a shell. This adds a "toolbox" container that, for now, just provides a BusyBox toolset so that the plugin startup script can run. It also provides a debug shell if the container doesn't ship with one. * Colorize stderr in plugin output. This replaces the shell-based plugin wrapper with a statically-compiled Go wrapper which monitors stdout and stderr. The output lines are serialized (i.e., if the plugin writes to stdout and stderr at the same time, the lines will be written separately) and colorized. This sets us up to implement more useful debug tooling such as result linting, logging, timeouts, etc. * Add basic linting of plugin results. * Build the toolkit separately in quit mode. The build process was generating quite a bit of output on every run. * Fix lint check for "truncated" field value. * Be consistent on "toolbox" (not "toolkit"). * Add comment about run-plugin. * Fix truncated comment.
- Loading branch information
1 parent
f8c06b1
commit 0c196eb
Showing
11 changed files
with
427 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
* | ||
!*.go | ||
!go.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# syntax=docker/dockerfile:1 | ||
|
||
FROM golang:1.23 AS builder | ||
|
||
WORKDIR /src/app | ||
|
||
COPY . . | ||
RUN --mount=type=cache,target=/go/pkg/mod \ | ||
--mount=type=cache,target=/root/.cache/go-build \ | ||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o run-plugin . | ||
|
||
# Distroless always uses the "latest" tag. | ||
# hadolint ignore=DL3007 | ||
FROM gcr.io/distroless/static-debian11:latest | ||
|
||
WORKDIR /opt/artemis-plugin-toolbox/bin | ||
|
||
# Install a statically-compiled BusyBox in the specific location. | ||
COPY --from=busybox:1.37.0-musl /bin/busybox . | ||
RUN ["./busybox", "--install", "."] | ||
|
||
# Install statically-compiled plugin wrapper. | ||
COPY --from=builder /src/app/run-plugin . | ||
|
||
# The container provides the volume; we don't need to run anything. | ||
VOLUME ["/opt/artemis-plugin-toolbox/bin"] | ||
ENTRYPOINT ["/opt/artemis-plugin-toolbox/bin/true"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Plugin Runner Toolbox | ||
|
||
Provides a common shell and debugging utilities for the plugin runner utility. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module github.com/warnermedia/artemis/backend/utilities/plugin_runner/toolbox | ||
|
||
go 1.23.3 | ||
|
||
require ( | ||
github.com/fatih/color v1.18.0 | ||
github.com/packntrack/jsonValidator v0.5.2 | ||
golang.org/x/sys v0.25.0 | ||
) | ||
|
||
require ( | ||
github.com/mattn/go-colorable v0.1.13 // indirect | ||
github.com/mattn/go-isatty v0.0.20 // indirect | ||
golang.org/x/text v0.14.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= | ||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= | ||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= | ||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= | ||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | ||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= | ||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||
github.com/packntrack/jsonValidator v0.5.2 h1:ZKp6019Ys4L291jCW7fbEXAsirVS0O7NefZ2nN6N9Z0= | ||
github.com/packntrack/jsonValidator v0.5.2/go.mod h1:UuNIDD2Y4e8lwJbUX7761SGZsDT129TqVI+ed9JkMrM= | ||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= | ||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= | ||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
"unicode/utf8" | ||
|
||
"github.com/packntrack/jsonValidator" | ||
) | ||
|
||
type LintErrors []error | ||
|
||
func (errs LintErrors) String() string { | ||
var sb strings.Builder | ||
sb.WriteRune('[') | ||
for i, e := range errs { | ||
if i > 0 { | ||
sb.WriteString(", ") | ||
} | ||
sb.WriteString(fmt.Sprintf("%#v", e.Error())) | ||
} | ||
sb.WriteRune(']') | ||
return sb.String() | ||
} | ||
|
||
// lint validates the JSON results from the plugin. | ||
func lint(buf []byte) LintErrors { | ||
var retv []error | ||
|
||
if !utf8.Valid(buf) { | ||
retv = append(retv, errors.New("invalid UTF-8")) | ||
return retv | ||
} | ||
|
||
var result struct { | ||
Success *bool `validations:"type=bool;required=true"` | ||
Truncated *bool `validations:"type=bool;required=true"` | ||
Details any `validations:"required=true"` | ||
Errors []string `validations:"type=[]string;required=true"` | ||
} | ||
|
||
errs := jsonValidator.Validate(buf, &result) | ||
retv = append(retv, errs...) | ||
|
||
if result.Truncated != nil && *result.Truncated { | ||
retv = append(retv, jsonValidator.ValidationError{ | ||
Field: "truncated", Message: "Must be false", | ||
}) | ||
} | ||
|
||
//TODO: Validate details based on plugin type. | ||
|
||
return retv | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package main | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
) | ||
|
||
// containsErr checks if there is an error in the list which contains all | ||
// of the specified substrings. | ||
func containsErr(errs []error, substrs ...string) bool { | ||
search: | ||
for _, e := range errs { | ||
for _, substr := range substrs { | ||
if !strings.Contains(e.Error(), substr) { | ||
continue search | ||
} | ||
} | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
func TestInvalidUTF8(t *testing.T) { | ||
actual := lint([]byte{0xff, 123, 125}) | ||
if !containsErr(actual, "invalid UTF-8") { | ||
t.Fatalf("expected UTF-8 error, got %v", actual) | ||
} | ||
} | ||
|
||
func TestNotObject(t *testing.T) { | ||
actual := lint([]byte(`"success"`)) | ||
if !containsErr(actual, "Field json", "invalid format") { | ||
t.Fatalf("expected type error, got %v", actual) | ||
} | ||
} | ||
|
||
func TestInvalidTypes(t *testing.T) { | ||
actual := lint([]byte(`{ | ||
"success": "yes", | ||
"errors": "bar" | ||
}`)) | ||
if !containsErr(actual, "Field success", "invalid format") { | ||
t.Fatalf("expected type error, got %v", actual) | ||
} | ||
if !containsErr(actual, "Field errors", "invalid format") { | ||
t.Fatalf("expected type error, got %v", actual) | ||
} | ||
} | ||
|
||
func TestTruncated(t *testing.T) { | ||
actual := lint([]byte(`{"truncated": true}`)) | ||
if !containsErr(actual, "Field truncated", "Must be false") { | ||
t.Fatalf("expected value error, got %v", actual) | ||
} | ||
} | ||
|
||
func TestRequiredFields(t *testing.T) { | ||
actual := lint([]byte(`{}`)) | ||
if !containsErr(actual, "Field success", "is required") { | ||
t.Fatalf("expected required error, got %v", actual) | ||
} | ||
if !containsErr(actual, "Field truncated", "is required") { | ||
t.Fatalf("expected required error, got %v", actual) | ||
} | ||
if !containsErr(actual, "Field details", "is required") { | ||
t.Fatalf("expected required error, got %v", actual) | ||
} | ||
if !containsErr(actual, "Field errors", "is required") { | ||
t.Fatalf("expected required error, got %v", actual) | ||
} | ||
} | ||
|
||
func TestValid(t *testing.T) { | ||
actual := lint([]byte(`{ | ||
"success": false, | ||
"truncated": false, | ||
"details": [{ | ||
"component": "foo", | ||
"source": "Dockerfile" | ||
}], | ||
"errors": ["failed to scan"] | ||
}`)) | ||
if len(actual) > 0 { | ||
t.Fatalf("expected no errors, got %v", actual) | ||
} | ||
} |
Oops, something went wrong.