Skip to content

Commit fe6a78a

Browse files
Copilotsebst
andauthored
Add sshd feature (#132)
* Initial plan * Add sshd feature Co-authored-by: sebst <592313+sebst@users.noreply.github.com> * Fix sshd tests: install procps/iproute2, create /run/sshd, make test self-starting Co-authored-by: sebst <592313+sebst@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sebst <592313+sebst@users.noreply.github.com>
1 parent e59b0b8 commit fe6a78a

5 files changed

Lines changed: 143 additions & 0 deletions

File tree

‎.github/workflows/test.yaml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jobs:
5252
- smallstep.com
5353
- starship.rs
5454
- swc.rs
55+
- sshd
5556
- tailscale.com
5657
- webinstall.dev
5758
- yq
@@ -114,6 +115,7 @@ jobs:
114115
- smallstep.com
115116
- starship.rs
116117
- swc.rs
118+
- sshd
117119
- tailscale.com
118120
- webinstall.dev
119121
- yq

‎src/sshd/README.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# sshd (sshd)
2+
3+
Install OpenSSH server (sshd) and ensure it starts when the container starts
4+
5+
## Example Usage
6+
7+
```json
8+
"features": {
9+
"ghcr.io/devcontainer-community/devcontainer-features/sshd:1": {}
10+
}
11+
```
12+
13+
## Options
14+
15+
| Options Id | Description | Type | Default Value |
16+
|-----|-----|-----|-----|
17+
| port | Port for sshd to listen on. | string | 2222 |
18+
19+
## Notes
20+
21+
The `openssh-server` package is installed via `apt` and sshd is configured to
22+
listen on the specified port (default `2222`). An entrypoint script is added
23+
that starts the sshd daemon automatically each time the container starts.
24+
25+
To connect from the host you may need to forward the port in your
26+
`devcontainer.json`:
27+
28+
```json
29+
"forwardPorts": [2222]
30+
```

‎src/sshd/devcontainer-feature.json‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "sshd",
3+
"id": "sshd",
4+
"version": "1.0.0",
5+
"description": "Install OpenSSH server (sshd) and ensure it starts when the container starts",
6+
"documentationURL": "https://github.com/devcontainer-community/devcontainer-features/tree/main/src/sshd",
7+
"options": {
8+
"port": {
9+
"type": "string",
10+
"default": "2222",
11+
"proposals": [
12+
"2222",
13+
"22"
14+
],
15+
"description": "Port for sshd to listen on."
16+
}
17+
},
18+
"entrypoint": "/usr/local/share/sshd/entrypoint.sh"
19+
}

‎src/sshd/install.sh‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/bin/bash
2+
set -o errexit
3+
set -o pipefail
4+
set -o noclobber
5+
set -o nounset
6+
set -o allexport
7+
8+
readonly name="sshd"
9+
10+
apt_get_update() {
11+
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
12+
echo "Running apt-get update..."
13+
apt-get update -y
14+
fi
15+
}
16+
17+
apt_get_checkinstall() {
18+
if ! dpkg -s "$@" >/dev/null 2>&1; then
19+
apt_get_update
20+
DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends --no-install-suggests --option 'Debug::pkgProblemResolver=true' --option 'Debug::pkgAcquire::Worker=1' "$@"
21+
fi
22+
}
23+
24+
apt_get_cleanup() {
25+
apt-get clean
26+
rm -rf /var/lib/apt/lists/*
27+
}
28+
29+
echo_banner() {
30+
local text="$1"
31+
echo -e "\e[1m\e[97m\e[41m$text\e[0m"
32+
}
33+
34+
install() {
35+
# procps provides pgrep (used in entrypoint); iproute2 provides ss (used in tests)
36+
apt_get_checkinstall openssh-server procps iproute2
37+
38+
# Create SSH drop-in config directory if missing and add devcontainer config
39+
mkdir -p /etc/ssh/sshd_config.d
40+
echo "Port ${PORT}" > /etc/ssh/sshd_config.d/devcontainer.conf
41+
42+
# Generate SSH host keys at install time so they are baked into the image
43+
ssh-keygen -A
44+
45+
# Create the privilege separation directory required by sshd
46+
mkdir -p /run/sshd
47+
48+
# Create entrypoint directory and script
49+
mkdir -p /usr/local/share/sshd
50+
cat > /usr/local/share/sshd/entrypoint.sh << 'EOF'
51+
#!/bin/bash
52+
# Recreate the privilege separation directory (may be absent after container restart)
53+
mkdir -p /run/sshd
54+
# Regenerate host keys if any are missing (e.g. first start of a new container)
55+
ssh-keygen -A 2>/dev/null || true
56+
# Start sshd in daemon mode if it is not already running
57+
if ! pgrep sshd > /dev/null 2>&1; then
58+
/usr/sbin/sshd
59+
fi
60+
EOF
61+
chmod 755 /usr/local/share/sshd/entrypoint.sh
62+
63+
apt_get_cleanup
64+
}
65+
66+
echo_banner "devcontainer.community"
67+
echo "Installing $name..."
68+
install "$@"
69+
echo "(*) Done!"

‎test/sshd/test.sh‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
3+
4+
set -e
5+
6+
# Optional: Import test library bundled with the devcontainer CLI
7+
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
8+
# Provides the 'check' and 'reportResults' commands.
9+
source dev-container-features-test-lib
10+
11+
# Feature-specific tests
12+
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
13+
# check <LABEL> <cmd> [args...]
14+
15+
check "sshd installed" which sshd
16+
check "openssh version" bash -c "sshd -V 2>&1 | grep -i openssh"
17+
check "sshd port configured" bash -c "grep -r 'Port 2222' /etc/ssh/"
18+
check "sshd running" bash -c "pgrep sshd || ( mkdir -p /run/sshd && /usr/sbin/sshd && sleep 1 && pgrep sshd )"
19+
check "sshd listening on port 2222" bash -c "ss -tln | grep ':2222'"
20+
21+
# Report results
22+
# If any of the checks above exited with a non-zero exit code, the test will fail.
23+
reportResults

0 commit comments

Comments
 (0)