Skip to content

Commit 2c367ec

Browse files
committed
feat: add CLI arguments, modular refactor, test reorganization, and security scanning
- Add CLI support with short/long options (-s/--size, -p/--profile, etc.) - Split diskmark.sh into lib/ modules (args, validate, utils, profiles, detect, benchmark, output, update) - Reorganize tests into 6 concurrent jobs with optimized timing (100ms/500ms) - Integrate Trivy and Grype security scanning into docker-image.yml workflow
1 parent f8ed615 commit 2c367ec

14 files changed

Lines changed: 1818 additions & 1222 deletions

.github/copilot-instructions.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Copilot Instructions for docker-diskmark
2+
3+
## Project Overview
4+
5+
Docker DiskMark is a fio-based disk benchmarking tool packaged as a minimal Docker container. It provides CrystalDiskMark-like functionality for Linux systems.
6+
7+
## Project Structure
8+
9+
```
10+
diskmark.sh # Main entry point (~100 lines)
11+
lib/
12+
├── args.sh # CLI argument parsing + help/version
13+
├── validate.sh # Input validation functions
14+
├── utils.sh # Utility functions (color, size conversion, cleanup)
15+
├── profiles.sh # Profile definitions (default, nvme, custom job)
16+
├── detect.sh # Drive/filesystem detection
17+
├── benchmark.sh # fio benchmark execution + warmup + result parsing
18+
├── output.sh # Output formatting (human/JSON/YAML/XML)
19+
└── update.sh # Update check functionality
20+
```
21+
22+
## Clean Code Principles
23+
24+
Follow these clean code principles when contributing:
25+
26+
### Single Responsibility
27+
- Each function should do one thing and do it well
28+
- Keep functions small and focused (ideally < 30 lines)
29+
- Separate concerns: parsing, validation, execution, output
30+
31+
### Meaningful Names
32+
- Use descriptive function names: `validate_size_string` not `check`
33+
- Use consistent naming conventions (snake_case for functions/variables)
34+
- Prefix validation functions with `validate_`
35+
- Prefix parsing functions with `parse_`
36+
37+
### DRY (Don't Repeat Yourself)
38+
- Extract common patterns into reusable functions
39+
- Use helper functions for repeated validation logic
40+
- Centralize error handling and output formatting
41+
42+
### Comments and Documentation
43+
- Functions should be self-documenting through clear names
44+
- Add comments only when explaining "why", not "what"
45+
- Keep help text and documentation in sync with code
46+
47+
### Error Handling
48+
- Fail fast with clear error messages
49+
- Validate inputs early before processing
50+
- Use consistent exit codes (0=success, 1=error)
51+
52+
### Code Organization
53+
- Group related functions together
54+
- Order: constants → helpers → validators → core logic → main
55+
- Keep configuration separate from logic
56+
57+
## Shell Script Best Practices
58+
59+
- Use `set -e` to exit on errors
60+
- Quote variables: `"$VAR"` not `$VAR`
61+
- Use `[[` for conditionals (bash)
62+
- Prefer `local` variables in functions
63+
- Use meaningful return codes
64+
- Avoid global state when possible
65+
66+
## Testing Guidelines
67+
68+
- All features should have corresponding tests in `.github/workflows/tests.yml`
69+
- Test both valid and invalid inputs
70+
- Test CLI arguments in all formats: `--key value`, `--key=value`, `-k value`
71+
- Use dry-run mode for input validation tests
72+
- Use minimal sizes/runtimes for actual benchmark tests
73+
74+
## Docker Best Practices
75+
76+
- Keep the container minimal (scratch-based)
77+
- Only include necessary binaries
78+
- Use multi-stage builds
79+
- Set appropriate defaults via ENV
80+
- Run as non-root user (65534:65534)
81+
82+
## Output Formats
83+
84+
The tool supports multiple output formats:
85+
- Human-readable (default): colored, with emojis
86+
- JSON: structured, machine-readable
87+
- YAML: structured, human-friendly
88+
- XML: structured, enterprise-compatible
89+
90+
When modifying output, ensure all formats are updated consistently.

.github/workflows/docker-image.yml

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ permissions:
1717
contents: read
1818
packages: write
1919
pull-requests: write
20+
security-events: write
2021

2122
env:
2223
PLATFORMS: linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x
2324

2425
jobs:
2526
build:
27+
name: Build and Push Docker Image
2628
runs-on: ubuntu-latest
29+
outputs:
30+
image_tag: ${{ steps.image.outputs.tag }}
2731
env:
2832
HAS_DOCKERHUB_SECRETS: ${{ github.event_name != 'pull_request' || github.repository == github.event.pull_request.head.repo.full_name }}
2933
steps:
@@ -66,10 +70,17 @@ jobs:
6670
id: version
6771
run: |
6872
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
69-
echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
73+
VERSION="${{ github.ref_name }}"
74+
VERSION="${VERSION#v}"
7075
else
71-
echo "version=${{ github.sha }}" >> $GITHUB_OUTPUT
76+
GIT_DESC=$(git describe --tags --always 2>/dev/null)
77+
if [[ "$GIT_DESC" =~ ^v?([0-9]+\.[0-9]+\.[0-9]+)-([0-9]+)-g([a-f0-9]+)$ ]]; then
78+
VERSION="${BASH_REMATCH[1]}-dev.${BASH_REMATCH[2]}+${BASH_REMATCH[3]}"
79+
else
80+
VERSION="0.0.0-dev+${GITHUB_SHA::7}"
81+
fi
7282
fi
83+
echo "version=$VERSION" >> $GITHUB_OUTPUT
7384
- name: Build and push Docker image
7485
uses: docker/build-push-action@v5
7586
with:
@@ -83,6 +94,15 @@ jobs:
8394
labels: ${{ steps.meta.outputs.labels }}
8495
build-args: |
8596
VERSION=${{ steps.version.outputs.version }}
97+
- name: Export image tag for scanning
98+
id: image
99+
run: |
100+
IMAGE_TAG="$(echo '${{ steps.meta.outputs.tags }}' | grep 'ghcr.io' | head -n1)"
101+
if [ -z "$IMAGE_TAG" ]; then
102+
IMAGE_TAG="${{ vars.GHCR_IMAGE }}:pr-${{ github.event.pull_request.number }}"
103+
fi
104+
echo "tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
105+
echo "Scanning image: $IMAGE_TAG"
86106
- name: Docker Scout
87107
id: docker-scout
88108
if: ${{ github.event_name == 'pull_request' }}
@@ -102,3 +122,55 @@ jobs:
102122
username: ${{ secrets.DOCKERHUB_USERNAME }}
103123
password: ${{ secrets.DOCKERHUB_TOKEN }}
104124
repository: ${{ vars.DOCKERHUB_IMAGE }}
125+
126+
trivy:
127+
name: Trivy Security Scan
128+
runs-on: ubuntu-latest
129+
needs: build
130+
steps:
131+
- name: Checkout
132+
uses: actions/checkout@v4
133+
- name: Login to GitHub Container Registry
134+
uses: docker/login-action@v3
135+
with:
136+
registry: ghcr.io
137+
username: ${{ github.repository_owner }}
138+
password: ${{ secrets.GITHUB_TOKEN }}
139+
- name: Run Trivy vulnerability scanner
140+
uses: aquasecurity/trivy-action@0.30.0
141+
with:
142+
image-ref: ${{ needs.build.outputs.image_tag }}
143+
format: sarif
144+
output: trivy-results.sarif
145+
severity: CRITICAL,HIGH,MEDIUM
146+
- name: Upload Trivy scan results
147+
uses: github/codeql-action/upload-sarif@v3
148+
if: always()
149+
with:
150+
sarif_file: trivy-results.sarif
151+
152+
grype:
153+
name: Grype Security Scan
154+
runs-on: ubuntu-latest
155+
needs: build
156+
steps:
157+
- name: Checkout
158+
uses: actions/checkout@v4
159+
- name: Login to GitHub Container Registry
160+
uses: docker/login-action@v3
161+
with:
162+
registry: ghcr.io
163+
username: ${{ github.repository_owner }}
164+
password: ${{ secrets.GITHUB_TOKEN }}
165+
- name: Run Grype vulnerability scanner
166+
uses: anchore/scan-action@v6.0.0
167+
id: scan
168+
with:
169+
image: ${{ needs.build.outputs.image_tag }}
170+
fail-build: false
171+
severity-cutoff: medium
172+
- name: Upload Grype scan results
173+
uses: github/codeql-action/upload-sarif@v3
174+
if: always()
175+
with:
176+
sarif_file: ${{ steps.scan.outputs.sarif }}

0 commit comments

Comments
 (0)