Social cloud hosting
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: working container isolation with Nix-built OCI images

- Flake produces `container` output using dockerTools.buildImage
- Includes full Nix closure (bash, deno, jq, coreutils, cacert)
- Fixed bundle path mapping in container executor
- Tested successfully with real bundle from ATProto PDS

Container execution verified:
- Bundle fetched from bsky.social PDS
- Code runs in isolated container
- Network access works (with permissions)
- JSON response returned

Co-Authored-By: Claude <noreply@anthropic.com>

+56 -48
+14 -40
internal/cli/build.go
··· 83 83 containerRuntime = "podman" 84 84 } 85 85 86 - // Find the container Dockerfile 87 - dockerfilePath := filepath.Join(flakePath, "..", "container", "Dockerfile") 88 - if _, err := os.Stat(dockerfilePath); err != nil { 89 - return fmt.Errorf("container Dockerfile not found at %s", dockerfilePath) 90 - } 91 - 92 - // Create temp build dir 93 - buildDir, err := os.MkdirTemp("", "at-rund-build-") 94 - if err != nil { 95 - return fmt.Errorf("failed to create build dir: %w", err) 96 - } 97 - defer os.RemoveAll(buildDir) 98 - 99 86 for _, runtime := range runtimes { 100 87 imageName := fmt.Sprintf("at-rund-%s:latest", runtime) 101 88 fmt.Printf("Building %s...\n", imageName) 102 89 103 90 runtimeDir := filepath.Join(flakePath, runtime) 104 - stagingDir := filepath.Join(buildDir, runtime) 105 - runtimeOutDir := filepath.Join(stagingDir, "runtime") 106 91 107 - if err := os.MkdirAll(runtimeOutDir, 0755); err != nil { 108 - return fmt.Errorf("failed to create staging dir: %w", err) 109 - } 92 + // Step 1: Build container image with Nix 93 + fmt.Printf(" [1/2] Building OCI image with Nix...\n") 94 + resultLink := filepath.Join(os.TempDir(), fmt.Sprintf("at-rund-%s-container", runtime)) 110 95 111 - // Step 1: Build with Nix 112 - fmt.Printf(" [1/2] Building with Nix...\n") 113 - resultLink := filepath.Join(stagingDir, "result") 114 - 115 - nixCmd := exec.Command("nix", "build", runtimeDir, "--out-link", resultLink) 96 + nixCmd := exec.Command("nix", "build", runtimeDir+"#container", "--out-link", resultLink) 116 97 nixCmd.Stdout = os.Stdout 117 98 nixCmd.Stderr = os.Stderr 118 99 if err := nixCmd.Run(); err != nil { 119 100 return fmt.Errorf("nix build failed for %s: %w", runtime, err) 120 101 } 121 102 122 - // Copy the result (dereferencing symlinks) 123 - cpCmd := exec.Command("cp", "-rL", resultLink+"/.", runtimeOutDir) 124 - if err := cpCmd.Run(); err != nil { 125 - return fmt.Errorf("failed to copy nix result: %w", err) 103 + // Step 2: Load into Docker/Podman 104 + fmt.Printf(" [2/2] Loading image into %s...\n", containerRuntime) 105 + loadCmd := exec.Command(containerRuntime, "load", "-i", resultLink) 106 + loadCmd.Stdout = os.Stdout 107 + loadCmd.Stderr = os.Stderr 108 + 109 + if err := loadCmd.Run(); err != nil { 110 + return fmt.Errorf("failed to load image for %s: %w", runtime, err) 126 111 } 127 112 128 - // Step 2: Build container 129 - fmt.Printf(" [2/2] Building container image...\n") 130 - dockerCmd := exec.Command(containerRuntime, "build", 131 - "-t", imageName, 132 - "-f", dockerfilePath, 133 - stagingDir, 134 - ) 135 - dockerCmd.Stdout = os.Stdout 136 - dockerCmd.Stderr = os.Stderr 137 - 138 - if err := dockerCmd.Run(); err != nil { 139 - return fmt.Errorf("container build failed for %s: %w", runtime, err) 140 - } 113 + // Clean up the result link 114 + os.Remove(resultLink) 141 115 142 116 fmt.Printf(" ✓ Built %s\n", imageName) 143 117 }
+5 -1
internal/vm/container.go
··· 102 102 func (p *ContainerPool) executeInContainer(req ExecuteRequest, runtime ContainerRuntime) (*ExecuteResponse, error) { 103 103 start := time.Now() 104 104 105 + // The bundle file is mounted at /bundle/<filename> 106 + bundleFile := filepath.Base(req.BundlePath) 107 + codePath := "/bundle/" + bundleFile 108 + 105 109 // Build the exec request JSON 106 110 execReq := ExecRequest{ 107 - CodePath: "/bundle/code.js", // Path inside container 111 + CodePath: codePath, 108 112 Endpoint: req.Endpoint, 109 113 Args: req.Args, 110 114 Permissions: req.Permissions,
+37 -7
nix/runtimes/deno/flake.nix
··· 68 68 echo "$REQUEST" | ${pkgs.deno}/bin/deno run $DENO_FLAGS ${executorScript} 69 69 ''; 70 70 71 - in { 72 - packages = { 73 - default = pkgs.symlinkJoin { 74 - name = "at-rund-deno-runtime"; 71 + # The runtime package (for direct Nix execution) 72 + runtime = pkgs.symlinkJoin { 73 + name = "at-rund-deno-runtime"; 74 + paths = [ 75 + pkgs.deno 76 + pkgs.jq 77 + at-run-exec 78 + ]; 79 + }; 80 + 81 + # OCI container image (for ContainerPool) 82 + container = pkgs.dockerTools.buildImage { 83 + name = "at-rund-deno"; 84 + tag = "latest"; 85 + 86 + copyToRoot = pkgs.buildEnv { 87 + name = "image-root"; 75 88 paths = [ 76 - pkgs.deno 77 - pkgs.jq 78 - at-run-exec 89 + runtime 90 + pkgs.bashInteractive 91 + pkgs.coreutils 92 + pkgs.cacert 79 93 ]; 94 + pathsToLink = [ "/bin" "/etc" "/share" ]; 80 95 }; 96 + 97 + config = { 98 + Cmd = [ "/bin/at-run-exec" ]; 99 + WorkingDir = "/bundle"; 100 + Env = [ 101 + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" 102 + "PATH=/bin" 103 + ]; 104 + }; 105 + }; 106 + 107 + in { 108 + packages = { 109 + default = runtime; 110 + inherit container; 81 111 }; 82 112 83 113 # For development