Skip to content

Commit

Permalink
config: prefer boxes dir to boxes file
Browse files Browse the repository at this point in the history
  • Loading branch information
nalgeon committed Nov 8, 2024
1 parent c77d483 commit 32d875e
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 21 deletions.
5 changes: 0 additions & 5 deletions configs/boxes.json

This file was deleted.

3 changes: 3 additions & 0 deletions configs/boxes/alpine.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"image": "codapi/alpine"
}
7 changes: 2 additions & 5 deletions docs/add-sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,11 @@ Build the image:
docker build --file images/python/Dockerfile --tag codapi/python:latest images/python/
```

And register the image as a Codapi _box_ in `configs/boxes.json`:
Then register the image as a Codapi _box_. To do this, we create `configs/boxes/python.json`:

```js
{
// ...
"python": {
"image": "codapi/python"
}
"image": "codapi/python"
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Make sure you install Codapi on a separate machine — this is a must for security reasons. Do not store any sensitive data or credentials on this machine. This way, even if someone runs malicious code that somehow escapes the isolated environment, they won't have access to your other machines and data.

Steps for Debian (11/12) or Ubuntu (20.04/22.04).
Steps for Debian (11+) or Ubuntu (20.04+).

1. Install necessary packages (as root):

Expand Down
2 changes: 1 addition & 1 deletion images/alpine/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.18
FROM alpine:3.20

RUN adduser --home /sandbox --disabled-password sandbox

Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func (cfg *Config) ToJSON() string {
// A sandbox command can contain multiple steps, each of which runs in a separate box.
// So the relation sandbox -> box is 1 -> 1+.
type Box struct {
Name string `json:"name"`
Image string `json:"image"`
Runtime string `json:"runtime"`
Host
Expand Down
62 changes: 53 additions & 9 deletions internal/config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

const (
configFilename = "config.json"
boxesFilename = "boxes.json"
boxesDirname = "boxes"
commandsDirname = "commands"
)

Expand All @@ -22,7 +22,7 @@ func Read(path string) (*Config, error) {
return nil, err
}

cfg, err = ReadBoxes(cfg, filepath.Join(path, boxesFilename))
cfg, err = ReadBoxes(cfg, filepath.Join(path, boxesDirname))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -51,8 +51,57 @@ func ReadConfig(path string) (*Config, error) {
return cfg, err
}

// ReadBoxes reads boxes config from a JSON file.
// ReadBoxes reads boxes config from the boxes dir
// or from the boxes.json file if the boxes dir does not exist.
func ReadBoxes(cfg *Config, path string) (*Config, error) {
var boxes map[string]*Box
var err error

if fileio.Exists(path) {
// prefer the boxes dir
boxes, err = readBoxesDir(path)
} else {
// fallback to boxes.json
boxes, err = readBoxesFile(path + ".json")
}
if err != nil {
return nil, err
}

for _, box := range boxes {
setBoxDefaults(box, cfg.Box)
}

cfg.Boxes = boxes
return cfg, nil

}

// readBoxesDir reads boxes config from the boxes dir.
func readBoxesDir(path string) (map[string]*Box, error) {
fnames, err := filepath.Glob(filepath.Join(path, "*.json"))
if err != nil {
return nil, err
}

boxes := make(map[string]*Box, len(fnames))
for _, fname := range fnames {
box, err := fileio.ReadJson[Box](fname)
if err != nil {
return nil, err
}
if box.Name == "" {
// use the filename as the box name if it's not set
box.Name = strings.TrimSuffix(filepath.Base(fname), ".json")
}
boxes[box.Name] = &box
}

return boxes, err
}

// readBoxesFile reads boxes config from the boxes.json file.
func readBoxesFile(path string) (map[string]*Box, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
Expand All @@ -64,12 +113,7 @@ func ReadBoxes(cfg *Config, path string) (*Config, error) {
return nil, err
}

for _, box := range boxes {
setBoxDefaults(box, cfg.Box)
}

cfg.Boxes = boxes
return cfg, err
return boxes, err
}

// ReadCommands reads commands config from a JSON file.
Expand Down
13 changes: 13 additions & 0 deletions internal/config/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ func TestRead(t *testing.T) {
if cfg.Step.User != "sandbox" {
t.Errorf("Step.User: expected sandbox, got %s", cfg.Step.User)
}

// alpine box
if _, ok := cfg.Boxes["custom-alpine"]; !ok {
t.Error("Boxes: missing my/alpine box")
}
if cfg.Boxes["custom-alpine"].Image != "custom/alpine" {
t.Errorf(
"Boxes[custom-alpine]: expected custom/alpine image, got %s",
cfg.Boxes["custom-alpine"].Image,
)
}

// python box
if _, ok := cfg.Boxes["python"]; !ok {
t.Error("Boxes: missing python box")
}
Expand Down
4 changes: 4 additions & 0 deletions internal/config/testdata/boxes/alpine.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "custom-alpine",
"image": "custom/alpine"
}
3 changes: 3 additions & 0 deletions internal/config/testdata/boxes/python.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"image": "codapi/python"
}

0 comments on commit 32d875e

Please sign in to comment.