Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ RunCommand is for initialization only. Daily execution and Files use Runtime and
native or bounded local capabilities. Docker's lack of a native renewable lease
does not remove service-owned hosted expiry and cleanup requirements.

The independent Docker Provider consumes an immutable Runtime image and retains
one caller-owned allocation reference through partial creation and cleanup. Persist
that reference before Create and serialize its lifecycle; resolve a lost response
with observed state, without rewriting bootstrap credentials or replaying startup.
Provider state is compute state, not public Environment readiness. Named Runtime
volumes need explicit owned cleanup after container removal. Initialization command
timeouts can leave processes alive and require allocation cleanup before reuse.
The [managed Runtime build and ownership contract](services/agents-api/deploy/codex/README.md#managed-runtime-image-and-docker-adapter)
does not itself enable public hosted admission or supply durable expiry.

Qualify the actual Docker/native sandbox before default cutover: real model
execution, file access, owned cancellation, restart with retained native history
and files, and rejection when required history is missing. Generated code and file
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,7 @@ check-agents-harness:

check-agents-harness-native:
./scripts/build-agents-harness.sh check

.PHONY: build-agents-runtime
build-agents-runtime:
./scripts/build-agents-runtime.sh
20 changes: 20 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ require (
github.com/BurntSushi/toml v1.6.0
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.5.3
github.com/bwmarrin/discordgo v0.29.0
github.com/containerd/errdefs v1.0.0
github.com/go-chi/chi/v5 v5.3.2
github.com/go-chi/httprate v0.16.0
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
github.com/jackc/pgx/v5 v5.10.0
github.com/larksuite/oapi-sdk-go/v3 v3.10.0
github.com/moby/moby/api v1.56.0
github.com/moby/moby/client v0.6.0
github.com/openai/openai-go/v3 v3.61.0
github.com/pressly/goose/v3 v3.27.3
github.com/robfig/cron/v3 v3.0.1
Expand All @@ -24,10 +27,27 @@ require (
)

require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.1.0 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/tidwall/gjson v1.19.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
go.opentelemetry.io/otel v1.44.0 // indirect
go.opentelemetry.io/otel/metric v1.44.0 // indirect
go.opentelemetry.io/otel/trace v1.44.0 // indirect
)

require (
Expand Down
27 changes: 27 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.5.3 h1:mFFeD2k8QE+pYd1uFik2XG85+vilL5uj9P5mHQTM1Xk=
github.com/aliyun/alibabacloud-oss-go-sdk-v2 v1.5.3/go.mod h1:FTzydeQVmR24FI0D6XWUOMKckjXehM/jgMn1xC+DA9M=
github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno=
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
github.com/go-chi/httprate v0.16.0 h1:8V5DH9j6pSK6UQoBsTpvMyFxycqaKEIToyPKzHJjUa8=
github.com/go-chi/httprate v0.16.0/go.mod h1:A8lo+qRhk+s9LiuP5saS7XCGDXRXMcrueq0NfIuCa/I=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
Expand Down Expand Up @@ -62,12 +77,22 @@ github.com/mattn/go-isatty v0.0.23 h1:cYwCQTQf3HB6xUC+BtyCLZNr7IzbOmoZbmssVNzSyi
github.com/mattn/go-isatty v0.0.23/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby/api v1.56.0 h1:GQzua3NA599ASSIICx0iFgiJeO9YkdDARvQsm23ZZuQ=
github.com/moby/moby/api v1.56.0/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk=
github.com/moby/moby/client v0.6.0 h1:AJjEB21QPbXSXjDsZorFBoDZPhMrfbpaPLgSMAW9Bgs=
github.com/moby/moby/client v0.6.0/go.mod h1:OCo00wNRyA3m4lmJ228W3JbyCN4ZNNYjpOXiJydBdcQ=
github.com/modelcontextprotocol/go-sdk v1.7.0 h1:yqjY2dsbKAC0LSuWZVBMrHgiG8ukXv6NRo0JiALay44=
github.com/modelcontextprotocol/go-sdk v1.7.0/go.mod h1:dL7u98E/zjJTGzEq+j30jQ8K2k1mb6LeAH4inEcSGts=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/openai/openai-go/v3 v3.61.0 h1:nMLuGFdKBF0sB3qFVNwE8kpBpenVN1ucYRoKcx7E1u0=
github.com/openai/openai-go/v3 v3.61.0/go.mod h1:ufI1+K+t0ijRB3gk8eztiw1crcDpsBuxRQL4sbLIrts=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pressly/goose/v3 v3.27.3 h1:pIglVHjw99r4e/hDHHwbl9vfOsDMqUokfkXo6+n/RxA=
Expand Down Expand Up @@ -111,6 +136,8 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
Expand Down
43 changes: 43 additions & 0 deletions scripts/build-agents-runtime.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
runtime_root="${PARSAR_HOME:-$HOME/.parsar}"
output_dir="${AGENTS_RUNTIME_BUILD_DIR:-$runtime_root/build/agents-runtime}"
# Extract the official @openai/codex@0.153.4-linux-x64 npm package here.
package_dir="${AGENTS_RUNTIME_CODEX_PACKAGE:?Set AGENTS_RUNTIME_CODEX_PACKAGE to the extracted pinned platform package}"
helpers_dir="${AGENTS_EXECUTOR_BUILD_DIR:-$runtime_root/build/agents-executor}"
for directory in "$runtime_root" "$output_dir" "$package_dir" "$helpers_dir"; do
if [[ "$directory" != /* ]]; then
printf 'Runtime build directories must be absolute: %s\n' "$directory" >&2
exit 1
fi
done
python3 - "$package_dir/package.json" <<'PY'
import json, sys
package = json.load(open(sys.argv[1]))
assert package['name'] == '@openai/codex' and package['version'] == '0.153.4-linux-x64', 'Expected pinned official Linux x64 package'
PY
native_dir="$package_dir/vendor/x86_64-unknown-linux-musl"
for executable in "$native_dir/bin/codex" "$helpers_dir/agents-api-codex-directory" "$helpers_dir/agents-api-codex-write"; do
test -x "$executable" || { printf 'Missing executable: %s\n' "$executable" >&2; exit 1; }
done
test -d "$native_dir/codex-resources"
mkdir -p "$runtime_root/cache/agents-runtime-builds"
context="$(mktemp -d "$runtime_root/cache/agents-runtime-builds/bundle.XXXXXX")"
trap 'rm -rf "$context"' EXIT
(
cd "$repo_root"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod=readonly -trimpath \
-o "$context/parsar-daemon" ./apps/parsar-daemon/cmd/parsar-daemon
)
cp "$helpers_dir/agents-api-codex-directory" "$helpers_dir/agents-api-codex-write" "$context/"
cp "$native_dir/bin/codex" "$context/codex"
cp -R "$native_dir/codex-resources" "$context/codex-resources"
cp "$repo_root/services/agents-api/deploy/codex/requirements.toml" "$context/requirements.toml"
cp "$repo_root/services/agents-api/deploy/codex/Dockerfile" "$context/Dockerfile"
# Preserve the previous bundle if compilation or validation failed.
mkdir -p "$output_dir"
cp -R "$context/." "$output_dir/"
printf 'Runtime image context: %s\n' "$output_dir"
printf 'Build with: docker build --platform linux/amd64 -t agents-runtime:local %q\n' "$output_dir"
24 changes: 24 additions & 0 deletions services/agents-api/deploy/codex/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Build context is a prepared binary bundle, never the product checkout.
# Native package and resources must both be Codex 0.153.4 (linux/amd64).
FROM debian:bookworm-slim@sha256:a0982977ea1cf754c15281f48a7d5957cd14039a2a4f2aca9f23d74d226003d0
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates bash git python3 nodejs npm ripgrep \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /environment /home/runtime \
&& groupadd --gid 1000 runtime \
&& useradd --uid 1000 --gid 1000 --home-dir /home/runtime --no-create-home runtime
COPY --chmod=0555 parsar-daemon agents-api-codex-directory agents-api-codex-write codex /usr/local/bin/
COPY codex-resources /usr/local/codex-resources
COPY requirements.toml /etc/codex/requirements.toml
RUN chmod 0555 /etc/codex && chmod 0444 /etc/codex/requirements.toml
ENV HOME=/home/runtime PARSAR_HOME=/home/runtime/.parsar \
PARSAR_CODEX_BIN=/usr/local/bin/codex PARSAR_CODEX_PERMISSION_PROFILE=managed-workspace \
PARSAR_RUNTIME_WORKSPACE=/environment/workspace \
PARSAR_RUNTIME_DIRECTORY_HELPER=/usr/local/bin/agents-api-codex-directory \
PARSAR_RUNTIME_WRITE_HELPER=/usr/local/bin/agents-api-codex-write \
PARSAR_RUNTIME_STAGING=/environment/staging
USER 1000:1000
RUN test -r /etc/codex/requirements.toml && test "$(codex --version)" = "codex-cli 0.153.4"
WORKDIR /environment/workspace
ENTRYPOINT ["/usr/local/bin/parsar-daemon"]
CMD ["connect", "--profile", "default"]
43 changes: 43 additions & 0 deletions services/agents-api/deploy/codex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,46 @@ Native tools retain their narrower filesystem policy. Qualify direct reads,
symlink and process-root aliases, attempted staging modification, real uploaded
bytes consumed by Codex, cancellation and retained-history restart before using
this writer profile for public admission. Configuration alone is not that proof.

## Managed Runtime image and Docker adapter

Build the existing Rust filesystem helpers with `make build-agents-executor`, and
extract the official npm package `@openai/codex@0.153.4-linux-x64` beneath
`~/.parsar/`. Set `AGENTS_RUNTIME_CODEX_PACKAGE` to its extracted `package` directory
and run `scripts/build-agents-runtime.sh`. It builds the existing daemon and
prepares a binary-only Docker context at `~/.parsar/build/agents-runtime`; build
that context with the printed Docker command. This initial image is Linux amd64.
The package includes the unmodified native executable and matching resources.
It does not contain the product server, product CLI, credentials or workspace data.

The service's `internal/sandbox` interface has five operations. Its Docker adapter
uses the official Moby Go client and an operator-selected immutable image digest,
network, installation UUID and the contents of this directory's `seccomp.json`.
The Runtime authenticates outward through the ordinary daemon bootstrap path;
`CoreURL` includes the existing `/api/v1` gateway prefix. The image's default
entrypoint is the same daemon connect command used by a user-managed Runtime.
No socket, host home or product configuration is mounted inside the Runtime.

The caller persists a fresh allocation UUID with the authorized tenant and
Environment before Create, and serializes lifecycle operations for that allocation.
Create returns the reference even on failure. Duplicate allocation creation does
not rewrite credentials or restart the container. After a lost response, inspect
the allocation and reconcile its actual state; do not blindly replay Create.
This adapter does not supply durable Core reconciliation or public hosted Session
admission. Those are required before switching the default hosted path.

Two labelled named volumes retain native state and the workspace/staging pair.
The trusted daemon auth profile is copied with restrictive permissions before
startup; it does not enter image layers, environment variables, labels or arguments.
GetInfo describes observed compute state, not daemon or native readiness. Docker
has no renewable provider lease: Renew verifies the allocation, while future Core
lifecycle integration must own expiry. Kill verifies allocation ownership, removes
the container, explicitly removes its named volumes and confirms absence. Keep the
reference and retry cleanup when an operation fails; an HTTP timeout is not proof
that a resource disappeared. Never use broad container or volume pruning.

RunCommand is for trusted initialization, using an explicit context deadline,
argument vector and nonroot user. It preserves nonzero status and limits each
output stream to1MiB. Disconnecting an exec stream does not stop the command:
an unconfirmed result requires allocation cleanup before reuse. Routine agent
execution, cancellation and Files continue through Core/daemon/Runtime.
62 changes: 62 additions & 0 deletions services/agents-api/internal/sandbox/docker/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package docker

import (
"archive/tar"
"bytes"
"context"
"encoding/json"
"io"

"github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/sandbox"
"github.com/moby/moby/client"
)

type entry struct {
name string
content []byte
directory bool
}

func (p *Provider) bootstrap(ctx context.Context, id string, b sandbox.Bootstrap) error {
// The existing daemon auth profile is the shared managed/user-managed boundary.
// This file is injected before the untrusted workspace or harness can run.
auth, e := json.Marshal(struct {
ServerURL string `json:"server_url"`
RuntimeID string `json:"runtime_id"`
Credential string `json:"runner_credential"`
}{b.CoreURL, b.DeviceID, b.Credential})
if e != nil {
return e
}
if e = p.copy(ctx, id, "/home", []entry{
{name: "runtime", directory: true}, {name: "runtime/.parsar", directory: true},
{name: "runtime/.parsar/parsar-daemon", directory: true},
{name: "runtime/.parsar/parsar-daemon/default", directory: true},
{name: "runtime/.parsar/parsar-daemon/default/auth.json", content: auth},
}); e != nil {
return e
}
return p.copy(ctx, id, "/environment", []entry{{name: "workspace", directory: true}, {name: "staging", directory: true}})
}
func (p *Provider) copy(ctx context.Context, id, path string, entries []entry) error {
var content bytes.Buffer
writer := tar.NewWriter(&content)
for _, file := range entries {
header := &tar.Header{Name: file.name, Uid: 1000, Gid: 1000, Mode: 0600, Size: int64(len(file.content)), Typeflag: tar.TypeReg}
if file.directory {
header.Mode = 0700
header.Typeflag = tar.TypeDir
}
if e := writer.WriteHeader(header); e != nil {
return e
}
if _, e := writer.Write(file.content); e != nil {
return e
}
}
if e := writer.Close(); e != nil {
return e
}
_, e := p.client.CopyToContainer(ctx, id, client.CopyToContainerOptions{DestinationPath: path, Content: io.Reader(&content), CopyUIDGID: true})
return e
}
Loading
Loading