Skip to content

Commit f8a8e73

Browse files
authored
Merge pull request #44 from FROSTR-ORG/feature/auth-env-hardening
auth/env hardening and reliability updates
2 parents 12698ac + 2daa6d2 commit f8a8e73

102 files changed

Lines changed: 5031 additions & 1458 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [ master, dev ]
5+
branches: [ main, dev ]
66
pull_request:
7-
branches: [ master, dev ]
7+
branches: [ main, dev ]
88

99
jobs:
1010
test:
@@ -17,14 +17,17 @@ jobs:
1717
- name: Setup Bun
1818
uses: oven-sh/setup-bun@v2
1919
with:
20-
bun-version: latest
20+
bun-version: 1.3.10
2121

2222
- name: Install dependencies
2323
run: bun install --frozen-lockfile
2424

2525
- name: Type check
2626
run: bun run tsc --noEmit
2727

28+
- name: Run unit tests
29+
run: bun run test:unit
30+
2831
- name: Build frontend
2932
run: bun run build
3033

@@ -54,7 +57,7 @@ jobs:
5457
- name: Setup Bun
5558
uses: oven-sh/setup-bun@v2
5659
with:
57-
bun-version: latest
60+
bun-version: 1.3.10
5861

5962
- name: Install dependencies
6063
run: bun install --frozen-lockfile
@@ -71,16 +74,51 @@ jobs:
7174
- name: Checkout code
7275
uses: actions/checkout@v4
7376

77+
- name: Setup Bun
78+
uses: oven-sh/setup-bun@v2
79+
with:
80+
bun-version: 1.3.10
81+
82+
- name: Install dependencies
83+
run: bun install --frozen-lockfile
84+
7485
- name: Run security audit
7586
run: |
76-
bun audit || true # Don't fail on audit issues for now
87+
audit_log="$(mktemp)"
88+
last_exit=0
89+
for attempt in 1 2 3; do
90+
if bun audit >"$audit_log" 2>&1; then
91+
cat "$audit_log"
92+
rm -f "$audit_log"
93+
exit 0
94+
else
95+
audit_exit=$?
96+
last_exit=$audit_exit
97+
last_attempt=$attempt
98+
if [ "$attempt" -lt 3 ]; then
99+
echo "bun audit failed (attempt $attempt), retrying..."
100+
sleep 5
101+
fi
102+
fi
103+
done
104+
105+
audit_output="$(cat "$audit_log")"
106+
echo "bun audit failed after ${last_attempt:-3} attempts with exit code ${last_exit}"
107+
if grep -Eiq 'network|registry|ENOTFOUND|ECONNREFUSED|EAI_AGAIN|ETIMEDOUT' <<< "$audit_output"; then
108+
echo "bun audit failed after retries due to network/registry error: $audit_output"
109+
else
110+
echo "bun audit failed after retries - vulnerabilities detected: $audit_output"
111+
fi
112+
rm -f "$audit_log"
113+
exit 1
77114
78115
- name: Check for secrets
79-
uses: trufflesecurity/trufflehog@main
116+
# Pinned to immutable commit (v3.93.4) for supply-chain safety.
117+
# Maintenance: periodically verify this SHA still corresponds to the intended upstream release.
118+
uses: trufflesecurity/trufflehog@7c0734f987ad0bb30ee8da210773b800ee2016d3
80119
with:
81120
path: ./
82121
extra_args: --debug --only-verified
83-
continue-on-error: true
84122

85123
docker:
86124
runs-on: ubuntu-latest
@@ -104,13 +142,13 @@ jobs:
104142

105143
- name: Test Docker image
106144
run: |
145+
set -euo pipefail
146+
trap 'docker stop test-container >/dev/null 2>&1 || true; docker rm test-container >/dev/null 2>&1 || true' EXIT
107147
docker run -d --name test-container -p 8002:8002 \
108148
-e AUTO_ADMIN_SECRET=true \
109149
igloo-server:test
110150
sleep 10
111-
curl -f http://localhost:8002/api/status || exit 1
112-
docker stop test-container
113-
docker rm test-container
151+
curl -f http://localhost:8002/api/status
114152
115153
- name: Build Umbrel Docker image
116154
uses: docker/build-push-action@v5
@@ -124,12 +162,12 @@ jobs:
124162

125163
- name: Test Umbrel Docker image
126164
run: |
165+
set -euo pipefail
166+
trap 'docker stop test-umbrel >/dev/null 2>&1 || true; docker rm test-umbrel >/dev/null 2>&1 || true' EXIT
127167
docker run -d --name test-umbrel -p 8003:8002 \
128168
-e ADMIN_SECRET=ci-admin-secret \
129169
-e ALLOWED_ORIGINS=http://localhost:8003 \
130170
-e TRUST_PROXY=true \
131171
igloo-server-umbrel:test
132172
sleep 10
133-
curl -f http://localhost:8003/api/status || exit 1
134-
docker stop test-umbrel
135-
docker rm test-umbrel
173+
curl -f http://localhost:8003/api/status

.github/workflows/release.yml

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: Release
22

33
on:
4-
push:
5-
branches: [ master ]
64
workflow_dispatch:
75
inputs:
86
version:
@@ -13,7 +11,7 @@ on:
1311
jobs:
1412
release:
1513
runs-on: ubuntu-latest
16-
if: github.ref == 'refs/heads/master' && github.event_name == 'workflow_dispatch'
14+
if: github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch'
1715
permissions:
1816
contents: write
1917
pull-requests: write
@@ -31,7 +29,7 @@ jobs:
3129
- name: Setup Bun
3230
uses: oven-sh/setup-bun@v2
3331
with:
34-
bun-version: latest
32+
bun-version: 1.3.10
3533

3634
- name: Install dependencies
3735
run: bun install --frozen-lockfile
@@ -73,6 +71,12 @@ jobs:
7371
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
7472
echo "version_number=${NEW_VERSION#v}" >> $GITHUB_OUTPUT
7573
74+
- name: Type check
75+
run: bun run tsc --noEmit
76+
77+
- name: Run backend tests
78+
run: bun run test:unit
79+
7680
- name: Build application
7781
run: bun run build
7882

@@ -83,25 +87,45 @@ jobs:
8387
echo "# CHANGELOG" > CHANGELOG.md
8488
echo "" >> CHANGELOG.md
8589
fi
86-
87-
# Add new version entry
90+
91+
VERSION="${{ steps.new_version.outputs.version_number }}"
8892
DATE=$(date +%Y-%m-%d)
89-
sed -i "3i\\## [${{ steps.new_version.outputs.version_number }}] - $DATE\\n" CHANGELOG.md
90-
91-
# Add commit messages since last tag
93+
if ! grep -Fq "## [${VERSION}]" CHANGELOG.md; then
94+
awk -v version="$VERSION" -v date="$DATE" '
95+
NR == 1 { print; print ""; print "## [" version "] - " date; print ""; next }
96+
{ print }
97+
' CHANGELOG.md > CHANGELOG.md.tmp
98+
mv CHANGELOG.md.tmp CHANGELOG.md
99+
fi
100+
101+
temp_changelog="$(mktemp)"
102+
103+
# Add commit messages since last tag (safe for special chars in subjects)
92104
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
93105
if [ -n "$LAST_TAG" ]; then
94-
echo "### Changes since $LAST_TAG:" >> temp_changelog.md
95-
git log --pretty=format:"- %s" $LAST_TAG..HEAD >> temp_changelog.md
106+
printf '### Changes since %s:\n' "$LAST_TAG" > "$temp_changelog"
107+
git log --pretty=format:'%s%x00' "$LAST_TAG..HEAD" \
108+
| tr '\0' '\n' \
109+
| awk 'NF { print "- " $0 }' >> "$temp_changelog"
96110
else
97-
echo "### Changes:" >> temp_changelog.md
98-
git log --pretty=format:"- %s" -n 10 >> temp_changelog.md
111+
printf '### Changes:\n' > "$temp_changelog"
112+
git log --pretty=format:'%s%x00' -n 10 \
113+
| tr '\0' '\n' \
114+
| awk 'NF { print "- " $0 }' >> "$temp_changelog"
99115
fi
100-
echo "" >> temp_changelog.md
101-
102-
# Insert changes into changelog
103-
sed -i "/## \[${{ steps.new_version.outputs.version_number }}\]/r temp_changelog.md" CHANGELOG.md
104-
rm temp_changelog.md
116+
printf '\n' >> "$temp_changelog"
117+
118+
# Insert changes into changelog after the current version heading
119+
awk -v target="## [${VERSION}]" -v insert_file="$temp_changelog" '
120+
{ print }
121+
$0 == target && !inserted {
122+
while ((getline line < insert_file) > 0) print line
123+
close(insert_file)
124+
inserted = 1
125+
}
126+
' CHANGELOG.md > CHANGELOG.md.tmp
127+
mv CHANGELOG.md.tmp CHANGELOG.md
128+
rm -f "$temp_changelog"
105129
106130
- name: Create release archive
107131
run: |
@@ -122,28 +146,33 @@ jobs:
122146
--exclude=.git \
123147
--exclude=release \
124148
--exclude=frontend \
125-
src static package.json bun.lock tsconfig.json dockerfile compose.yml README.md LICENSE
149+
src static package.json bun.lock tsconfig.json Dockerfile compose.yml README.md LICENSE
126150
127151
- name: Create release tag
128152
run: |
129153
# Create git tag for release (works with branch protection)
130-
# Note: Version changes are not committed back to master due to branch protection
154+
# Note: Version changes are not committed back to main due to branch protection
131155
# The release archives will contain the correct versions
132-
git tag ${{ steps.new_version.outputs.new_version }}
133-
git push origin ${{ steps.new_version.outputs.new_version }}
156+
TAG="${{ steps.new_version.outputs.new_version }}"
157+
git fetch --tags origin
158+
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
159+
echo "Tag ${TAG} already exists, skipping tag creation"
160+
else
161+
git tag "${TAG}"
162+
git push origin "${TAG}"
163+
fi
134164
135-
- name: Create GitHub Release
136-
uses: actions/create-release@v1
137-
id: create_release
165+
- name: Create GitHub release and upload assets
166+
uses: softprops/action-gh-release@v2
138167
env:
139168
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140169
with:
141170
tag_name: ${{ steps.new_version.outputs.new_version }}
142-
release_name: Release ${{ steps.new_version.outputs.new_version }}
171+
name: Release ${{ steps.new_version.outputs.new_version }}
143172
body: |
144173
## Changes in ${{ steps.new_version.outputs.new_version }}
145174
146-
See [CHANGELOG.md](https://github.com/FROSTR-ORG/igloo-server/blob/master/CHANGELOG.md) for full details.
175+
See [CHANGELOG.md](https://github.com/FROSTR-ORG/igloo-server/blob/main/CHANGELOG.md) for full details.
147176
148177
### Installation
149178
@@ -162,36 +191,21 @@ jobs:
162191
```
163192
draft: false
164193
prerelease: false
165-
166-
- name: Upload source archive
167-
uses: actions/upload-release-asset@v1
168-
env:
169-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
170-
with:
171-
upload_url: ${{ steps.create_release.outputs.upload_url }}
172-
asset_path: ./release/igloo-server-${{ steps.new_version.outputs.version_number }}-src.tar.gz
173-
asset_name: igloo-server-${{ steps.new_version.outputs.version_number }}-src.tar.gz
174-
asset_content_type: application/gzip
175-
176-
- name: Upload binary archive
177-
uses: actions/upload-release-asset@v1
178-
env:
179-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
180-
with:
181-
upload_url: ${{ steps.create_release.outputs.upload_url }}
182-
asset_path: ./release/igloo-server-${{ steps.new_version.outputs.version_number }}.tar.gz
183-
asset_name: igloo-server-${{ steps.new_version.outputs.version_number }}.tar.gz
184-
asset_content_type: application/gzip
194+
files: |
195+
./release/igloo-server-${{ steps.new_version.outputs.version_number }}-src.tar.gz
196+
./release/igloo-server-${{ steps.new_version.outputs.version_number }}.tar.gz
185197
186198
docker:
187199
runs-on: ubuntu-latest
188200
needs: release
201+
permissions:
202+
packages: write
189203

190204
steps:
191205
- name: Checkout code
192206
uses: actions/checkout@v4
193207
with:
194-
ref: master
208+
ref: refs/tags/${{ needs.release.outputs.new_version }}
195209

196210
- name: Set up Docker Buildx
197211
uses: docker/setup-buildx-action@v3

.github/workflows/umbrel-dev.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Umbrel Dev Image
33
on:
44
push:
55
branches:
6-
- master
6+
- main
77
- dev
88
workflow_dispatch:
99

@@ -39,11 +39,16 @@ jobs:
3939

4040
- name: Smoke test Umbrel image
4141
run: |
42+
set -e
43+
cleanup() {
44+
docker rm -f umbrel-dev-test >/dev/null 2>&1 || true
45+
}
46+
trap cleanup EXIT
47+
4248
docker run -d --name umbrel-dev-test -p 8003:8002 \
4349
-e ADMIN_SECRET=ci-admin-secret \
4450
-e ALLOWED_ORIGINS=http://localhost:8003 \
4551
-e TRUST_PROXY=true \
4652
igloo-server-umbrel:dev-ci
4753
sleep 12
4854
curl -f http://localhost:8003/api/status
49-
docker rm -f umbrel-dev-test

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ dist
4040
static/app.js
4141
static/app.css
4242
static/styles.css
43+
static/docs/swagger-ui-bundle.js
44+
static/docs/swagger-ui-bundle.js.map
4345
static/qr-scanner-worker.min.js
4446

4547
# VSCode
@@ -64,7 +66,7 @@ data/.session-secret
6466
test-*.sh
6567
debug-*.js
6668
verify-*.md
67-
.DS_Store
69+
test-results/
6870

6971
# LLM files
7072
.claude

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Multi-stage build for smaller production image
2-
FROM oven/bun:latest AS build
2+
FROM oven/bun:1.3.10 AS build
33

44
WORKDIR /app
55

@@ -21,7 +21,7 @@ COPY tsconfig.json ./
2121
RUN bun run build
2222

2323
# --- Production stage ---
24-
FROM oven/bun:latest AS production
24+
FROM oven/bun:1.3.10 AS production
2525

2626
WORKDIR /app
2727

0 commit comments

Comments
 (0)