FAQ: secure operations with Univio Airlock
Secure container operation within Univio Airlock
This FAQ explains how to configure and operate devcontainer-based workspaces in Airlock.
FAQ
What is the minimum .devcontainer/devcontainer.json configuration Airlock expects?
Airlock auto-detection only needs the file to exist at .devcontainer/devcontainer.json. For practical use, include at least name and either image or build.
{
"name": "Airlock Dev",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04"
}
Should I place .devcontainer/devcontainer.json at the repository root or inside a subfolder?
Use the repository root. Airlock currently checks only this path:
.devcontainer/devcontainer.json
If your real setup is in subfolders, keep a root config that points to your target folder.
{
"name": "Airlock Monorepo",
"workspaceFolder": "/workspace/airlock/services/tunnel-client",
"image": "mcr.microsoft.com/devcontainers/typescript-node:22"
}
How does Univio Airlock detect whether my repository supports devcontainers?
On workspace init, Airlock checks the repo for .devcontainer/devcontainer.json and tries refs in this order: HEAD, main, master.
When does Univio Airlock enable the containers capability for a workspace?
When Univio Airlock detects a devcontainer file, Airlock requests capabilities: ["containers"] on create, and also tries to patch existing workspaces.
{
"gitUrl": "https://git.example.com/team/repo.git",
"capabilities": ["containers"]
}
Can I force-enable or disable the containers capability manually?
Yes. Use workspace settings in UI or patch via API.
curl -X PATCH "https://airlock.example.com/api/workspaces/<workspace-id>" \
-H "Authorization: Bearer <id-token>" \
-H "Content-Type: application/json" \
-d '{"capabilities":["containers"]}'
Disable:
curl -X PATCH "https://airlock.example.com/api/workspaces/<workspace-id>" \
-H "Authorization: Bearer <id-token>" \
-H "Content-Type: application/json" \
-d '{"capabilities":[]}'
What happens if my repository does not have a .devcontainer/devcontainer.json file?
The workspace is created without containers capability and runs in the standard workspace mode.
{
"gitUrl": "https://git.example.com/team/repo.git"
}
Which base image should I choose for a devcontainer in Airlock?
Start from official devcontainer images and pin versions. Choose by stack, not by distro preference.
{
"name": "Node 22",
"image": "mcr.microsoft.com/devcontainers/typescript-node:22"
}
For polyglot projects:
{
"name": "Polyglot",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04"
}
How do I install Node.js, Python, Java, or other tools inside the devcontainer?
Prefer devcontainer features for standard toolchains.
{
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "22" },
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" },
"ghcr.io/devcontainers/features/java:1": { "version": "21" }
}
}
How do I persist tools and dependencies across workspace restarts?
Persist through declarative config (image, Dockerfile, features), not manual setup. Keep project dependencies in repo-managed lockfiles.
{
"name": "Airlock Dev",
"build": {
"dockerfile": "Dockerfile"
},
"postCreateCommand": "npm ci"
}
FROM mcr.microsoft.com/devcontainers/typescript-node:22
RUN npm i -g pnpm@10.6.0
Should I install project tools in the devcontainer image or in postCreateCommand?
Rule of thumb: install stable toolchain in image; install repo dependencies in postCreateCommand.
{
"postCreateCommand": "npm ci --no-audit --no-fund",
"postStartCommand": "git config --get user.email >/dev/null || true"
}
How do I make sure everyone on the team uses the same tool versions?
Pin everything that affects builds and tests.
{
"image": "mcr.microsoft.com/devcontainers/typescript-node:22",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "22.14.0" }
}
}
{
"engines": {
"node": "22.x"
}
}
How do I configure postCreateCommand and postStartCommand for reliable setup?
Keep commands idempotent and fail fast.
{
"postCreateCommand": "bash .devcontainer/post-create.sh",
"postStartCommand": "bash .devcontainer/post-start.sh"
}
#!/usr/bin/env bash
set -euo pipefail
npm ci --no-audit --no-fund
How do I keep devcontainer startup fast for large repositories?
Move heavy installs to image build, keep startup hooks small, and avoid rebuilding unchanged layers.
FROM mcr.microsoft.com/devcontainers/typescript-node:22
RUN apt-get update && apt-get install -y --no-install-recommends ripgrep jq && rm -rf /var/lib/apt/lists/*
{
"postCreateCommand": "npm ci --prefer-offline"
}
How do I debug a failing devcontainer up in Airlock?
Run devcontainer up manually in the workspace and inspect output.
cd /workspace/<repo>
devcontainer up --workspace-folder /workspace/<repo> --log-level trace
If workspace fails to start, then disable container support first to force a standard workspace to spawn.
How do I run tests in Airlock?
Use Docker wrapper commands from your repo root or run through the devcontainer.
docker run --rm \
-v "$PWD/services/tunnel-client:/app" \
-v "airlock-tunnel-client-node-modules:/app/node_modules" \
-w /app node:24-alpine \
sh -lc "npm ci --no-audit --no-fund && npm run test"
Or, when your devcontainer is up:
devcontainer exec --workspace-folder /workspace/airlock -- npm run --prefix services/tunnel-client test
Should package.json scripts stay node-native, or should they call Docker commands?
Keep package.json scripts node-native. Put Docker wrappers in Makefile or scripts/.
{
"scripts": {
"test": "tsx --test src/**/*.test.ts",
"build": "tsc"
}
}
tunnel-client-test:
docker run --rm -v "$(PWD)/services/tunnel-client:/app" -w /app node:24-alpine sh -lc "npm ci && npm run test"
How should I structure Makefile targets for running service tests in Airlock?
Use a generic pattern in repository root and pass service name.
NODE_IMAGE ?= node:24-alpine
svc-ci:
@test -n "$(SERVICE)"
docker run --rm \
-v "$(PWD)/services/$(SERVICE):/app" \
-v "airlock-$(SERVICE)-node-modules:/app/node_modules" \
-w /app $(NODE_IMAGE) \
sh -lc "npm ci --no-audit --no-fund && npm run test && npm run build"
Usage:
make svc-ci SERVICE=tunnel-client
How do I expose application ports from the devcontainer to code-server and browser access?
For app preview ports, add platform-level routing explicitly.
{
"forwardPorts": [3000, 5173],
"portsAttributes": {
"3000": { "label": "API" },
"5173": { "label": "Frontend" }
}
}
Can I enforce a fail-closed policy so workspaces do not run outside devcontainer mode?
Yes. You can configure it at environment level among other compliance requirements.
How do I use Docker-in-Docker safely inside an Airlock devcontainer workspace?
Prefer one daemon and least privilege. In Airlock, core already runs Docker daemon; avoid nested daemons unless required.
{
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
]
}
Validate access:
docker info
docker run --rm hello-world
How do I use Docker Compose from inside the devcontainer?
Install Docker CLI with Compose plugin and use normal Compose workflow.
docker compose version
docker compose -f docker-compose.yml up -d
docker compose ps
How do I securely pass secrets and environment variables into the devcontainer?
Store secrets in Airlock variables, inject them into workspace env, then map them into devcontainer env variables.
{
"containerEnv": {
"NPM_TOKEN": "${localEnv:NPM_TOKEN}",
"PIP_INDEX_URL": "${localEnv:PIP_INDEX_URL}"
}
}
Never commit secrets to .devcontainer/devcontainer.json or Git.
How do I configure access to private package registries inside the devcontainer?
Reference tokens through environment variables and repo-local config files.
# .npmrc
@your-scope:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
pip config set global.index-url "$PIP_INDEX_URL"
How do I update devcontainer configuration without breaking existing workspaces?
Use additive changes, pin versions, and roll out in small steps.
git checkout -b feat/devcontainer-update
# edit .devcontainer/devcontainer.json
git commit -m "devcontainer: add node 22 feature"
Test with a fresh workspace before merge.
How do I roll back to a previous devcontainer setup if a change causes issues?
Revert .devcontainer changes and recreate workspace.
git log -- .devcontainer
git revert <bad-commit-sha>
Then create or restart workspace to apply previous config.
How should we connect local developer workflow, Airlock workflow, and GitLab CI so they stay consistent?
Keep one command contract:
npmscripts are canonical (test,build).- Airlock convenience wrappers call those scripts via Docker/devcontainer.
- GitLab CI runs the same scripts in
teststage beforebuild.
stages:
- test
- build
test_tunnel_client:
stage: test
image: node:24-alpine
script:
- cd services/tunnel-client
- npm ci --no-audit --no-fund
- npm run test
- npm run build