Skip to content

Commit c422bef

Browse files
committed
feat: initial commit
0 parents  commit c422bef

File tree

13 files changed

+403
-0
lines changed

13 files changed

+403
-0
lines changed

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: "dc.release"
2+
on:
3+
workflow_dispatch:
4+
5+
jobs:
6+
deploy:
7+
if: ${{ github.ref == 'refs/heads/main' }}
8+
runs-on: ubuntu-latest
9+
permissions:
10+
contents: write
11+
pull-requests: write
12+
packages: write
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Log in to Docker Hub
17+
uses: docker/login-action@v3
18+
with:
19+
username: ${{ secrets.ACTIONS_DOCKER_USERNAME }}
20+
password: ${{ secrets.ACTIONS_DOCKER_PASSWORD }}
21+
22+
- name: "Publish Features"
23+
uses: devcontainers/action@v1
24+
with:
25+
publish-features: "true"
26+
base-path-to-features: "./src"
27+
oci-registry: "docker.io"
28+
features-namespace: "pairspaces"
29+
generate-docs: "true"
30+
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: "dc.test"
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
workflow_dispatch:
8+
9+
jobs:
10+
test-autogenerated:
11+
runs-on: ubuntu-latest
12+
continue-on-error: true
13+
strategy:
14+
matrix:
15+
features:
16+
- pairspaces
17+
baseImage:
18+
- debian:latest
19+
- ubuntu:latest
20+
- mcr.microsoft.com/devcontainers/base:ubuntu
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: "Install latest devcontainer CLI"
25+
run: npm install -g @devcontainers/cli
26+
27+
- name: "Generating tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'"
28+
run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} .
29+
30+
test-scenarios:
31+
runs-on: ubuntu-latest
32+
continue-on-error: true
33+
strategy:
34+
matrix:
35+
features:
36+
- pairspaces
37+
steps:
38+
- uses: actions/checkout@v4
39+
40+
- name: "Install latest devcontainer CLI"
41+
run: npm install -g @devcontainers/cli
42+
43+
- name: "Generating tests for '${{ matrix.features }}' scenarios"
44+
run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated --skip-duplicated .
45+
46+
test-global:
47+
runs-on: ubuntu-latest
48+
continue-on-error: true
49+
steps:
50+
- uses: actions/checkout@v4
51+
52+
- name: "Install latest devcontainer CLI"
53+
run: npm install -g @devcontainers/cli
54+
55+
- name: "Testing global scenarios"
56+
run: devcontainer features test --global-scenarios-only .

.github/workflows/validate.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: "dc.validate"
2+
on:
3+
workflow_dispatch:
4+
pull_request:
5+
6+
jobs:
7+
validate:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
12+
- name: "Validate devcontainer-feature.json files"
13+
uses: devcontainers/action@v1
14+
with:
15+
validate-only: "true"
16+
base-path-to-features: "./src"

.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
node_modules/
2+
package-lock.json
3+
pnpm-lock.yaml
4+
yarn.lock
5+
6+
__pycache__/
7+
*.pyc
8+
9+
.DS_Store
10+
*.swp
11+
*.swo
12+
*.bak
13+
*.tmp
14+
15+
/dist/
16+
out/
17+
*.log
18+
19+
.test-containers/
20+
.vscode/
21+
22+
.env
23+
.env.local
24+
.envrc
25+
26+
build/
27+
bin/

LICENCE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Copyright © 2025 Interaction, LLC
2+
3+
All rights reserved.
4+
5+
This software and its source code (“Software”) are the property of Interaction, LLC
6+
and are protected by applicable copyright and intellectual property laws.
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy
9+
of this Software, to use it solely in the manner and for the purposes expressly
10+
authorized by Interaction, LLC. Any other use, including but not limited to
11+
modification, reproduction, distribution, sublicensing, or creation of
12+
derivative works, is strictly prohibited without prior written permission
13+
from Interaction, LLC.
14+
15+
The Software is licensed, not sold. No ownership rights are transferred.
16+
17+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
20+
21+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
22+
DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR
23+
OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE
24+
OR OTHER DEALINGS IN THE SOFTWARE.

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.PHONY: deploy
2+
deploy:
3+
devcontainer features publish -r ghcr.io -n pairspaces/devcontainers ./src --log-level trace
4+
5+
.PHONY: test
6+
test:
7+
devcontainer features test --features pairspaces --project-folder .
8+

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# DevContainers for PairSpaces
2+
3+
Use PairSpaces (https://docs.pairspaces.com) and work together with your team using DevContainers (see https://containers.dev).
4+
5+
## Description
6+
7+
The PairSpaces Devcontainer Feature configures a Devcontainer as a Space where you can work together with your team from the same Devcontainer. Learn more about working together from our [documentation](https://docs.pairspaces.com).
8+
9+
## Usage
10+
11+
In your `.devcontainer.json`:
12+
13+
```json
14+
{
15+
...,
16+
"features": {
17+
"ghcr.io/pairspaces/devcontainers/pairspaces": {
18+
"token": "[OUTPUT from `pair spaces authorize` HERE]"
19+
}
20+
},
21+
"postAttachCommand": "/opt/pair/pair spaces bootstrap",
22+
"remoteUser": "root",
23+
...
24+
}
25+
```
26+
27+
## Issues
28+
29+
You can open an issue [here](https://github.com/pairspaces/devcontainers/issues) or email us at support at pairspaces dot com.
30+
31+
## Licence
32+
33+
See LICENCE.md
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"id": "pairspaces",
3+
"version": "1.2.3",
4+
"name": "PairSpaces for DevContainers",
5+
"description": "Installs the PairSpaces CLI and bootstraps the DevContainer into a Space.",
6+
"documentationURL": "https://docs.pairspaces.com/spaces/new/container",
7+
"keywords": ["pair", "collaborate"],
8+
"options": {
9+
"token": {
10+
"default": "CHANGE_ME",
11+
"type": "string",
12+
"description": "Authorization token provided by `pair spaces authorize`"
13+
}
14+
},
15+
"postStartCommand": "sudo /usr/bin/supervisord -c /etc/supervisor/supervisord.conf"
16+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
AuthorizedKeysCommand /opt/pair/pair verify %u %k %t
2+
AuthorizedKeysCommandUser root
3+
PasswordAuthentication no
4+
Port __PORT__
5+
Subsystem sftp /usr/libexec/openssh/sftp-server

src/pairspaces/install.sh

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/bin/bash
2+
set -e
3+
4+
PAIR_ENV="latest"
5+
PAIR_VERSION="2.4.5"
6+
PORT="${VAR_PORT:-2222}"
7+
PAIR_CLI_URL="https://s3.amazonaws.com/downloads.pairspaces.com/cli/$PAIR_ENV/linux/amd64/pair_${PAIR_VERSION}"
8+
PAIR_CLI_PATH="/opt/pair/pair"
9+
SSHD_CONFIG_TEMPLATE="files/sshd_config.template"
10+
SSHD_CONFIG_TARGET="/etc/ssh/ps_sshd_config"
11+
SUPERVISOR_CONF_DIR="/etc/supervisor/conf.d"
12+
SUPERVISORD_MAIN_CONF="/etc/supervisor/supervisord.conf"
13+
TOKEN="${TOKEN:-CHANGED_ME}"
14+
15+
16+
install_packages() {
17+
local retries=3
18+
until apt-get update; do
19+
((retries--))
20+
[[ $retries -le 0 ]] && echo "apt-get update failed after retries" && exit 1
21+
echo "Retrying apt-get update..."
22+
sleep 3
23+
done
24+
25+
retries=3
26+
until DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
27+
openssh-server curl ca-certificates sudo gnupg iproute2 libkmod2 supervisor; do
28+
((retries--))
29+
[[ $retries -le 0 ]] && echo "apt-get install failed after retries" && exit 1
30+
echo "Retrying apt-get install..."
31+
apt-get update --fix-missing
32+
sleep 3
33+
done
34+
}
35+
36+
install_pair_cli() {
37+
mkdir -p "$(dirname "$PAIR_CLI_PATH")"
38+
curl -fsSL "$PAIR_CLI_URL" -o "$PAIR_CLI_PATH"
39+
chmod +x "$PAIR_CLI_PATH"
40+
}
41+
42+
configure_sshd() {
43+
mkdir -p /var/run/sshd /etc/ssh
44+
45+
if [[ -f "$SSHD_CONFIG_TEMPLATE" ]]; then
46+
sed "s/__PORT__/${PORT}/g" "$SSHD_CONFIG_TEMPLATE" > "$SSHD_CONFIG_TARGET"
47+
else
48+
echo "No sshd config found"
49+
exit 1
50+
fi
51+
52+
ssh-keygen -A
53+
}
54+
55+
configure_supervisord() {
56+
mkdir -p "$SUPERVISOR_CONF_DIR"
57+
58+
cat <<EOF > "${SUPERVISOR_CONF_DIR}/sshd.conf"
59+
[program:sshd]
60+
command=/usr/sbin/sshd -D -e -f $SSHD_CONFIG_TARGET
61+
autostart=true
62+
autorestart=true
63+
stderr_logfile=/var/log/sshd.err.log
64+
stdout_logfile=/var/log/sshd.out.log
65+
EOF
66+
67+
cat <<EOF > "$SUPERVISORD_MAIN_CONF"
68+
[supervisord]
69+
nodaemon=false
70+
user=root
71+
logfile=/var/log/supervisord.log
72+
pidfile=/var/run/supervisord.pid
73+
74+
[include]
75+
files = $SUPERVISOR_CONF_DIR/*.conf
76+
EOF
77+
}
78+
79+
write_token() {
80+
if [[ -z "$TOKEN" ]]; then
81+
echo "TOKEN is not set. This feature requires a token."
82+
exit 1
83+
fi
84+
85+
mkdir -p "$(dirname "$PAIR_CLI_PATH")"
86+
echo "$TOKEN" > "/opt/pair/bootstrap.txt"
87+
}
88+
89+
main() {
90+
install_packages
91+
install_pair_cli
92+
configure_sshd
93+
configure_supervisord
94+
write_token
95+
}
96+
97+
main "$@"

0 commit comments

Comments
 (0)