fix: separate runner token from API token, proper workdir

- RUNNER_TOKEN env for act_runner registration (separate from GITEA_TOKEN)
- Create /opt/runner/work as workdir_parent (fixes .cache path error)
- Runner config via .runner.yaml with explicit workdir
- IMDSv2 for instance metadata
- PATH includes /usr/local/go/bin
This commit is contained in:
2026-05-22 20:22:55 +01:00
parent 69d04b9ea7
commit e728a8d819
3 changed files with 36 additions and 16 deletions
Binary file not shown.
Binary file not shown.
+36 -16
View File
@@ -110,28 +110,28 @@ var labelToSpot = map[string]spotConfig{
// --- Config from env --- // --- Config from env ---
type cfg struct { type cfg struct {
GiteaURL string GiteaURL string
GiteaToken string GiteaToken string // API token (for fetching workflows, setting commit status)
ExecFnName string RunnerToken string // Runner registration token (for act_runner register)
AMI string // pre-baked AMI with Go, Node, Docker, AWS CLI, act_runner ExecFnName string
Subnet string AMI string // pre-baked AMI with Go, Node, Docker, AWS CLI, act_runner
SecurityGroup string Subnet string
DDBTable string SecurityGroup string
DDBTable string
InstanceProfile string InstanceProfile string
Region string
} }
func loadCfg() cfg { func loadCfg() cfg {
return cfg{ return cfg{
GiteaURL: os.Getenv("GITEA_URL"), GiteaURL: os.Getenv("GITEA_URL"),
GiteaToken: os.Getenv("GITEA_TOKEN"), GiteaToken: os.Getenv("GITEA_TOKEN"),
RunnerToken: os.Getenv("RUNNER_TOKEN"),
ExecFnName: os.Getenv("EXECUTOR_FUNCTION_NAME"), ExecFnName: os.Getenv("EXECUTOR_FUNCTION_NAME"),
AMI: os.Getenv("RUNNER_AMI"), AMI: os.Getenv("RUNNER_AMI"),
Subnet: os.Getenv("SUBNET"), Subnet: os.Getenv("SUBNET"),
SecurityGroup: os.Getenv("SECURITY_GROUP"), SecurityGroup: os.Getenv("SECURITY_GROUP"),
DDBTable: os.Getenv("DDB_TABLE"), DDBTable: os.Getenv("DDB_TABLE"),
InstanceProfile: os.Getenv("INSTANCE_PROFILE"), // IAM instance profile ARN InstanceProfile: os.Getenv("INSTANCE_PROFILE"),
Region: os.Getenv("AWS_REGION"),
} }
} }
@@ -144,8 +144,11 @@ set -euo pipefail
exec > /var/log/tinqs-ci.log 2>&1 exec > /var/log/tinqs-ci.log 2>&1
echo "=== Tinqs CI Runner: %s ===" echo "=== Tinqs CI Runner: %s ==="
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
REGION=%s # Get instance metadata (IMDSv2)
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
REGION=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)
# Self-termination trap — kill instance on exit (success or failure) # Self-termination trap — kill instance on exit (success or failure)
cleanup() { cleanup() {
@@ -154,8 +157,12 @@ cleanup() {
} }
trap cleanup EXIT trap cleanup EXIT
# act_runner is pre-installed in the AMI at /usr/local/bin/act_runner # Source Go/Node paths from AMI
cd /tmp export PATH=$PATH:/usr/local/go/bin
export HOME=/root
# Create proper working directory for act_runner
mkdir -p /opt/runner && cd /opt/runner
# Register as ephemeral runner (picks one job, then exits) # Register as ephemeral runner (picks one job, then exits)
act_runner register --no-interactive \ act_runner register --no-interactive \
@@ -164,11 +171,24 @@ act_runner register --no-interactive \
--name %s \ --name %s \
--labels "%s:host" --labels "%s:host"
# Configure runner to use /opt/runner as workdir
cat > .runner.yaml << 'RUNCFG'
log:
level: info
runner:
capacity: 1
timeout: 30m
host:
workdir_parent: /opt/runner/work
RUNCFG
mkdir -p /opt/runner/work
# Run — blocks until the job completes, then exits (ephemeral mode) # Run — blocks until the job completes, then exits (ephemeral mode)
act_runner daemon act_runner daemon --config .runner.yaml
echo "=== Runner exited, cleanup will terminate instance ===" echo "=== Runner exited, cleanup will terminate instance ==="
`, runnerName, c.Region, c.GiteaURL, c.GiteaToken, runnerName, label) `, runnerName, c.GiteaURL, c.RunnerToken, runnerName, label)
return base64.StdEncoding.EncodeToString([]byte(script)) return base64.StdEncoding.EncodeToString([]byte(script))
} }