osbuild: add shell.init stage
Add support for the org.osbuild.shell.init stage and test validator.
This commit is contained in:
parent
636f3ff237
commit
2fcf3582b5
2 changed files with 241 additions and 0 deletions
57
internal/osbuild/shell_init_stage.go
Normal file
57
internal/osbuild/shell_init_stage.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package osbuild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const filenameRegex = "^[a-zA-Z0-9\\.\\-_]{1,250}$"
|
||||
const envVarRegex = "^[A-Z][A-Z0-9_]*$"
|
||||
|
||||
type ShellInitStageOptions struct {
|
||||
Files map[string]ShellInitFile `json:"files"`
|
||||
}
|
||||
|
||||
func (ShellInitStageOptions) isStageOptions() {}
|
||||
|
||||
func (options ShellInitStageOptions) validate() error {
|
||||
fre := regexp.MustCompile(filenameRegex)
|
||||
vre := regexp.MustCompile(envVarRegex)
|
||||
for fname, kvs := range options.Files {
|
||||
if !fre.MatchString(fname) {
|
||||
return fmt.Errorf("filename %q doesn't conform to schema (%s)", fname, filenameRegex)
|
||||
}
|
||||
|
||||
if len(kvs.Env) == 0 {
|
||||
return fmt.Errorf("at least one environment variable must be specified for each file")
|
||||
}
|
||||
|
||||
for _, kv := range kvs.Env {
|
||||
if !vre.MatchString(kv.Key) {
|
||||
return fmt.Errorf("variable name %q doesn't conform to schema (%s)", kv.Key, envVarRegex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ShellInitFile struct {
|
||||
Env []EnvironmentVariable `json:"env"`
|
||||
}
|
||||
|
||||
type EnvironmentVariable struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
func NewShellInitStage(options *ShellInitStageOptions) *Stage {
|
||||
if err := options.validate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &Stage{
|
||||
Type: "org.osbuild.shell.init",
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
184
internal/osbuild/shell_init_stage_test.go
Normal file
184
internal/osbuild/shell_init_stage_test.go
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
package osbuild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidShellInitStageOptions(t *testing.T) {
|
||||
tests := []ShellInitStageOptions{
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"filename": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "KEY",
|
||||
Value: "value",
|
||||
},
|
||||
{
|
||||
Key: "KEY2",
|
||||
Value: "value2",
|
||||
},
|
||||
{
|
||||
Key: "EMPTY",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
"filename2": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "KEY21",
|
||||
Value: "value21",
|
||||
},
|
||||
{
|
||||
Key: "KEY22",
|
||||
Value: "value22",
|
||||
},
|
||||
{
|
||||
Key: "EMPTY",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"gawk.sh": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "AWKPATH",
|
||||
Value: "$AWKPATH:$*",
|
||||
},
|
||||
{
|
||||
Key: "AWKLIBPATH",
|
||||
Value: "$AWKLIBPATH:$*",
|
||||
},
|
||||
},
|
||||
},
|
||||
"flatpak.sh": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "XDG_DATA_DIRS",
|
||||
Value: "${new_dirs:+${new_dirs}:}${XDG_DATA_DIRS:-/usr/local/share:/usr/share}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
for idx := range tests {
|
||||
tt := tests[idx]
|
||||
name := fmt.Sprintf("ValidShellInitStage-%d", idx)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert.NoErrorf(tt.validate(), "%q returned an error [idx: %d]", name, idx)
|
||||
assert.NotPanics(func() { NewShellInitStage(&tt) })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidShellInitStageOptions(t *testing.T) {
|
||||
tests := []ShellInitStageOptions{
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
|
||||
"path/filename": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "DOESNT",
|
||||
Value: "matter",
|
||||
},
|
||||
},
|
||||
},
|
||||
"ok": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "EMPTYOK",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"gawk.sh": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "",
|
||||
Value: "badkey",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"$FILENAME": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "BAD",
|
||||
Value: "filename",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"FILENAME": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "bad.var",
|
||||
Value: "okval",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"FILENAME": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "BAD.VAR",
|
||||
Value: "okval",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"me.sh": {
|
||||
Env: []EnvironmentVariable{
|
||||
{
|
||||
Key: "-SH",
|
||||
Value: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Files: map[string]ShellInitFile{
|
||||
"empty.sh": {},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert := assert.New(t)
|
||||
for idx := range tests {
|
||||
tt := tests[idx]
|
||||
name := fmt.Sprintf("InvalidShellInitStage-%d", idx)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert.Errorf(tt.validate(), "%q didn't return an error [idx: %d]", name, idx)
|
||||
assert.Panics(func() { NewShellInitStage(&tt) })
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue