Skip to content

Commit e454ca8

Browse files
committed
init version to support python
0 parents  commit e454ca8

File tree

8 files changed

+1134
-0
lines changed

8 files changed

+1134
-0
lines changed

.github/workflows/build.yml

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
name: Build and Push Docker Images with Nix
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
schedule:
9+
- cron: '0 2 * * 1' # Weekly on Monday at 2 AM
10+
workflow_dispatch:
11+
inputs:
12+
push_images:
13+
description: 'Push images to registry'
14+
type: boolean
15+
default: true
16+
17+
env:
18+
REGISTRY: ghcr.io
19+
IMAGE_NAME: reaslab/docker-python-uv
20+
21+
jobs:
22+
build:
23+
runs-on: fedora-latest
24+
permissions:
25+
contents: read
26+
packages: write
27+
id-token: write
28+
attestations: write
29+
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@v4
33+
34+
- name: Set up Nix
35+
uses: cachix/install-nix-action@v22
36+
with:
37+
nix_path: nixpkgs=channel:nixos-unstable
38+
39+
- name: Install Nix dependencies
40+
run: |
41+
nix-env -iA nixpkgs.dockerTools
42+
nix-env -iA nixpkgs.gnutar
43+
nix-env -iA nixpkgs.gzip
44+
45+
- name: Build Docker image with Nix
46+
run: |
47+
nix-build docker.nix --option sandbox false
48+
49+
- name: Set up Docker Buildx
50+
uses: docker/setup-buildx-action@v3
51+
52+
- name: Log in to Container Registry
53+
if: github.event.inputs.push_images != 'false'
54+
uses: docker/login-action@v3
55+
with:
56+
registry: ${{ env.REGISTRY }}
57+
username: ${{ github.actor }}
58+
password: ${{ secrets.GITHUB_TOKEN }}
59+
60+
- name: Load Docker image
61+
run: |
62+
docker load < result
63+
64+
- name: Extract metadata
65+
id: meta
66+
if: github.event.inputs.push_images != 'false'
67+
uses: docker/metadata-action@v5
68+
with:
69+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
70+
tags: |
71+
type=raw,value=secure-latest
72+
73+
- name: Tag Docker image
74+
if: github.event.inputs.push_images != 'false'
75+
run: |
76+
# Get the image ID from the loaded image
77+
IMAGE_ID=$(docker images --format "{{.ID}}" | head -1)
78+
echo "Image ID: $IMAGE_ID"
79+
80+
# Tag with all metadata tags
81+
for tag in ${{ steps.meta.outputs.tags }}; do
82+
echo "Tagging with: $tag"
83+
docker tag $IMAGE_ID $tag
84+
done
85+
86+
- name: Push Docker image
87+
if: github.event.inputs.push_images != 'false'
88+
run: |
89+
for tag in ${{ steps.meta.outputs.tags }}; do
90+
echo "Pushing: $tag"
91+
docker push $tag
92+
done
93+
94+
- name: Run security scan
95+
if: github.event.inputs.push_images != 'false'
96+
uses: aquasecurity/trivy-action@master
97+
with:
98+
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest
99+
format: 'sarif'
100+
output: 'trivy-results.sarif'
101+
102+
- name: Upload Trivy scan results
103+
if: github.event.inputs.push_images != 'false'
104+
uses: github/codeql-action/upload-sarif@v2
105+
with:
106+
sarif_file: 'trivy-results.sarif'
107+
108+
test:
109+
runs-on: fedora-latest
110+
needs: build
111+
if: github.event.inputs.push_images != 'false'
112+
113+
steps:
114+
- name: Test Python version
115+
run: |
116+
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python --version
117+
118+
- name: Test UV installation
119+
run: |
120+
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest uv --version
121+
122+
- name: Test security restrictions
123+
run: |
124+
# Test that dangerous modules are restricted
125+
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python -c "
126+
try:
127+
import os
128+
print('ERROR: os module should be restricted')
129+
exit(1)
130+
except ImportError:
131+
print('OK: os module is properly restricted')
132+
"
133+
134+
- name: Test Gurobi availability
135+
run: |
136+
# Test that Gurobi is available (without license)
137+
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python -c "
138+
try:
139+
import gurobipy
140+
print('OK: Gurobi Python package is available')
141+
except ImportError as e:
142+
print(f'ERROR: Gurobi not available: {e}')
143+
exit(1)
144+
"
145+
146+
- name: Test scientific packages
147+
run: |
148+
# Test that scientific packages are available
149+
docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:secure-latest python -c "
150+
import numpy
151+
import scipy
152+
import pandas
153+
import matplotlib
154+
import sklearn
155+
print('OK: All scientific packages are available')
156+
print(f'NumPy version: {numpy.__version__}')
157+
print(f'SciPy version: {scipy.__version__}')
158+
print(f'Pandas version: {pandas.__version__}')
159+
"
160+
161+
cleanup:
162+
runs-on: fedora-latest
163+
needs: [build, test]
164+
if: always() && github.event.inputs.push_images != 'false'
165+
166+
permissions:
167+
packages: write
168+
169+
steps:
170+
- name: Clean up old images
171+
uses: dataaxiom/ghcr-cleanup-action@v1
172+
with:
173+
token: ${{ secrets.GITHUB_TOKEN }}
174+
package-name: ${{ env.IMAGE_NAME }}
175+
keep-versions: 10
176+
177+
generate-summary:
178+
runs-on: fedora-latest
179+
needs: [build, test]
180+
if: always()
181+
182+
steps:
183+
- name: Generate summary
184+
run: |
185+
echo "## 🐳 Docker Image Build Summary" >> $GITHUB_STEP_SUMMARY
186+
echo "" >> $GITHUB_STEP_SUMMARY
187+
echo "**Image:** \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
188+
echo "" >> $GITHUB_STEP_SUMMARY
189+
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
190+
echo "- \`secure-latest\`" >> $GITHUB_STEP_SUMMARY
191+
echo "" >> $GITHUB_STEP_SUMMARY
192+
echo "**Features:**" >> $GITHUB_STEP_SUMMARY
193+
echo "- ✅ Secure Python 3.12 environment" >> $GITHUB_STEP_SUMMARY
194+
echo "- ✅ UV package manager" >> $GITHUB_STEP_SUMMARY
195+
echo "- ✅ Gurobi optimization solver" >> $GITHUB_STEP_SUMMARY
196+
echo "- ✅ Scientific computing packages" >> $GITHUB_STEP_SUMMARY
197+
echo "- ✅ Non-root user execution" >> $GITHUB_STEP_SUMMARY
198+
echo "- ✅ Resource limits and security restrictions" >> $GITHUB_STEP_SUMMARY
199+
echo "" >> $GITHUB_STEP_SUMMARY
200+
echo "**Registry:** [GitHub Container Registry](https://github.com/orgs/reaslab/packages)" >> $GITHUB_STEP_SUMMARY

.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Nix build artifacts
2+
result
3+
result-*
4+
5+
# Docker build artifacts
6+
.dockerignore
7+
8+
# IDE files
9+
.vscode/
10+
.idea/
11+
*.swp
12+
*.swo
13+
*~
14+
15+
# OS files
16+
.DS_Store
17+
Thumbs.db
18+
19+
# Logs
20+
*.log
21+
22+
# Temporary files
23+
*.tmp
24+
*.temp
25+
26+
# Gurobi license (keep private)
27+
gurobi.lic
28+
*.lic
29+
30+
# Test files
31+
test/
32+
*.pyc
33+
__pycache__/
34+
.pytest_cache/
35+
36+
# Environment files
37+
.env
38+
.env.local
39+
.env.*.local
40+
41+
# Backup files
42+
*.bak
43+
*.backup

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 ReasLab
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Makefile for docker-python-uv (Nix-based, Fedora runners)
2+
3+
.PHONY: help build test clean push pull run run-secure dev
4+
5+
# Default values
6+
REGISTRY ?= ghcr.io
7+
IMAGE_NAME ?= reaslab/docker-python-uv
8+
TAG ?= secure-latest
9+
10+
help: ## Show this help message
11+
@echo "Available targets:"
12+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
13+
14+
build: ## Build Docker image using Nix
15+
@echo "Building Docker image using Nix..."
16+
@echo "This will build a secure Python environment with UV and Gurobi"
17+
./build.sh
18+
19+
test: ## Test the built Docker image
20+
@echo "Testing Docker image..."
21+
@echo "Testing Python version..."
22+
docker run --rm $(IMAGE_NAME):$(TAG) python --version
23+
@echo "Testing UV installation..."
24+
docker run --rm $(IMAGE_NAME):$(TAG) uv --version
25+
@echo "Testing security restrictions..."
26+
docker run --rm $(IMAGE_NAME):$(TAG) python -c "try: import os; print('ERROR: os should be restricted'); exit(1); except ImportError: print('OK: os is restricted')"
27+
@echo "Testing Gurobi availability..."
28+
docker run --rm $(IMAGE_NAME):$(TAG) python -c "import gurobipy; print('OK: Gurobi available')"
29+
@echo "Testing scientific packages..."
30+
docker run --rm $(IMAGE_NAME):$(TAG) python -c "import numpy, scipy, pandas; print('OK: Scientific packages available')"
31+
32+
clean: ## Clean up Docker images and Nix build artifacts
33+
@echo "Cleaning up..."
34+
docker rmi $(IMAGE_NAME):$(TAG) 2>/dev/null || true
35+
docker image prune -f 2>/dev/null || true
36+
rm -f result 2>/dev/null || true
37+
@echo "Cleanup completed"
38+
39+
push: ## Push Docker images to registry
40+
@echo "Pushing Docker images to registry..."
41+
docker push $(IMAGE_NAME):$(TAG)
42+
43+
pull: ## Pull Docker images from registry
44+
@echo "Pulling Docker images from registry..."
45+
docker pull $(IMAGE_NAME):$(TAG)
46+
47+
run: ## Run interactive container
48+
@echo "Running interactive container..."
49+
docker run --rm -it $(IMAGE_NAME):$(TAG) bash
50+
51+
run-secure: ## Run secure Python interpreter
52+
@echo "Running secure Python interpreter..."
53+
docker run --rm -it $(IMAGE_NAME):$(TAG) python
54+
55+
dev: ## Run development container with volume mount
56+
@echo "Running development container with volume mount..."
57+
docker run --rm -it -v $(PWD):/app $(IMAGE_NAME):$(TAG) bash
58+
59+
gurobi-test: ## Test Gurobi with license file
60+
@echo "Testing Gurobi with license file..."
61+
@if [ ! -f "gurobi.lic" ]; then \
62+
echo "Error: gurobi.lic file not found. Please place your Gurobi license file in the current directory."; \
63+
exit 1; \
64+
fi
65+
docker run --rm -v $(PWD)/gurobi.lic:/app/gurobi.lic:ro $(IMAGE_NAME):$(TAG) python -c "import gurobipy; print('Gurobi version:', gurobipy.gurobi.version())"
66+
67+
nix-shell: ## Enter Nix shell for development
68+
@echo "Entering Nix shell..."
69+
nix-shell -p nixpkgs.dockerTools nixpkgs.gnutar nixpkgs.gzip
70+
71+
info: ## Show image information
72+
@echo "Image Information:"
73+
@echo " Registry: $(REGISTRY)"
74+
@echo " Image: $(IMAGE_NAME)"
75+
@echo " Tag: $(TAG)"
76+
@echo " Full name: $(REGISTRY)/$(IMAGE_NAME):$(TAG)"
77+
@echo ""
78+
@echo "Available commands:"
79+
@echo " make build - Build the image"
80+
@echo " make test - Test the image"
81+
@echo " make run - Run interactive container"
82+
@echo " make dev - Run with volume mount"
83+
@echo " make clean - Clean up images"

0 commit comments

Comments
 (0)