Skip to content

Commit 82365b1

Browse files
authored
Merge pull request #10 from shubham-stepsecurity/sm/feat/migrate
feat(mdm): migrate script to go module
2 parents e9e5cee + d96ec13 commit 82365b1

57 files changed

Lines changed: 6455 additions & 276 deletions

Some content is hidden

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

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ body:
1010
- type: input
1111
id: version
1212
attributes:
13-
label: Script Version
14-
description: "Run: ./stepsecurity-dev-machine-guard.sh --version"
15-
placeholder: "1.8.1"
13+
label: Version
14+
description: "Run: ./stepsecurity-dev-machine-guard --version"
15+
placeholder: "1.9.0"
1616
validations:
1717
required: true
1818
- type: input
@@ -28,7 +28,7 @@ body:
2828
attributes:
2929
label: Command Run
3030
description: The exact command you ran
31-
placeholder: "./stepsecurity-dev-machine-guard.sh --json"
31+
placeholder: "./stepsecurity-dev-machine-guard --json"
3232
validations:
3333
required: true
3434
- type: textarea

.github/pull_request_template.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
## Testing
1212

1313
- [ ] Tested on macOS (version: ___)
14-
- [ ] Script runs without errors: `./stepsecurity-dev-machine-guard.sh --verbose`
15-
- [ ] JSON output is valid: `./stepsecurity-dev-machine-guard.sh --json | python3 -m json.tool`
14+
- [ ] Binary runs without errors: `./stepsecurity-dev-machine-guard --verbose`
15+
- [ ] JSON output is valid: `./stepsecurity-dev-machine-guard --json | python3 -m json.tool`
1616
- [ ] No secrets or credentials included
17-
- [ ] ShellCheck passes (if script was modified)
17+
- [ ] Lint passes: `make lint`
18+
- [ ] Tests pass: `make test`
1819

1920
## Related Issues
2021

.github/workflows/release.yml

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ jobs:
99
release:
1010
name: Build, Sign & Release
1111
runs-on: ubuntu-latest
12-
environment: release
1312
permissions:
14-
contents: write # create tag, release, and upload assets
15-
id-token: write # Sigstore OIDC keyless signing
16-
attestations: write # SLSA build provenance
13+
contents: write # create tag, release, and upload assets
14+
id-token: write # OIDC token for cosign keyless signing and build provenance
15+
attestations: write # SLSA build provenance
1716

1817
steps:
1918
- name: Harden the runner (Audit all outbound calls)
@@ -23,13 +22,15 @@ jobs:
2322

2423
- name: Checkout repository
2524
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25+
with:
26+
fetch-depth: 0
2627

27-
- name: Extract version from script
28+
- name: Extract version from source
2829
id: version
2930
run: |
30-
version=$(grep -m1 '^AGENT_VERSION=' stepsecurity-dev-machine-guard.sh | sed 's/AGENT_VERSION="//;s/"//')
31+
version=$(grep -m1 'Version.*=' internal/buildinfo/version.go | sed 's/.*"\(.*\)".*/\1/')
3132
if [ -z "$version" ]; then
32-
echo "::error::Could not extract AGENT_VERSION from script"
33+
echo "::error::Could not extract Version from internal/buildinfo/version.go"
3334
exit 1
3435
fi
3536
tag="v${version}"
@@ -40,52 +41,98 @@ jobs:
4041
- name: Check tag does not already exist
4142
run: |
4243
if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
43-
echo "::error::Tag ${{ steps.version.outputs.tag }} already exists. Bump AGENT_VERSION in the script before releasing."
44+
echo "::error::Tag ${{ steps.version.outputs.tag }} already exists. Bump Version in internal/buildinfo/version.go before releasing."
4445
exit 1
4546
fi
4647
48+
- name: Create tag
49+
run: |
50+
git config user.name "github-actions[bot]"
51+
git config user.email "github-actions[bot]@users.noreply.github.com"
52+
git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
53+
git push origin "${{ steps.version.outputs.tag }}"
54+
55+
- name: Set up Go
56+
uses: actions/setup-go@v5
57+
with:
58+
go-version-file: go.mod
59+
60+
- name: Run GoReleaser
61+
uses: goreleaser/goreleaser-action@v6
62+
with:
63+
distribution: goreleaser
64+
version: latest
65+
args: release --clean
66+
env:
67+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
68+
4769
- name: Install cosign
4870
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
4971

50-
- name: Sign script with Sigstore (keyless)
72+
- name: Prepare release artifacts for signing
5173
run: |
52-
cosign sign-blob stepsecurity-dev-machine-guard.sh \
53-
--bundle stepsecurity-dev-machine-guard.sh.bundle \
54-
--yes
74+
# Copy binaries to match the exact names users download from the release.
75+
# GoReleaser uploads as name_template (e.g. stepsecurity-dev-machine-guard_darwin_amd64)
76+
# but keeps them in build subdirs locally. We copy to dist/ with release names
77+
# so cosign signs the same bytes users verify against.
78+
AMD64_SRC=$(find dist -type f -name 'stepsecurity-dev-machine-guard' -path '*darwin_amd64*' | head -1)
79+
ARM64_SRC=$(find dist -type f -name 'stepsecurity-dev-machine-guard' -path '*darwin_arm64*' | head -1)
5580
56-
- name: Verify signature
81+
for label in "amd64:${AMD64_SRC}" "arm64:${ARM64_SRC}"; do
82+
name="${label%%:*}"
83+
path="${label#*:}"
84+
if [ -z "$path" ] || [ ! -f "$path" ]; then
85+
echo "::error::Binary not found for ${name}"
86+
find dist -type f
87+
exit 1
88+
fi
89+
done
90+
91+
cp "$AMD64_SRC" dist/stepsecurity-dev-machine-guard_darwin_amd64
92+
cp "$ARM64_SRC" dist/stepsecurity-dev-machine-guard_darwin_arm64
93+
echo "Prepared release artifacts for signing"
94+
95+
- name: Sign artifacts with Sigstore (keyless)
5796
run: |
58-
cosign verify-blob stepsecurity-dev-machine-guard.sh \
59-
--bundle stepsecurity-dev-machine-guard.sh.bundle \
60-
--certificate-identity-regexp "github.com/step-security/dev-machine-guard" \
61-
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
97+
cosign sign-blob dist/stepsecurity-dev-machine-guard_darwin_amd64 \
98+
--bundle dist/stepsecurity-dev-machine-guard_darwin_amd64.bundle --yes
99+
cosign sign-blob dist/stepsecurity-dev-machine-guard_darwin_arm64 \
100+
--bundle dist/stepsecurity-dev-machine-guard_darwin_arm64.bundle --yes
101+
cosign sign-blob stepsecurity-dev-machine-guard.sh \
102+
--bundle dist/stepsecurity-dev-machine-guard.sh.bundle --yes
62103
63104
- name: Generate checksums
64105
run: |
65-
sha256sum stepsecurity-dev-machine-guard.sh > checksums.txt
66-
sha256sum stepsecurity-dev-machine-guard.sh.bundle >> checksums.txt
67-
echo "Checksums:"
68-
cat checksums.txt
106+
# Separate checksum file for cosign-signed artifacts (script + bundles).
107+
# GoReleaser already generates checksums for the Go binaries in its own SHA256SUMS file.
108+
sha256sum dist/stepsecurity-dev-machine-guard_darwin_amd64 > dist/cosign-checksums.txt
109+
sha256sum dist/stepsecurity-dev-machine-guard_darwin_arm64 >> dist/cosign-checksums.txt
110+
sha256sum stepsecurity-dev-machine-guard.sh >> dist/cosign-checksums.txt
69111
70-
- name: Create tag
112+
- name: Upload signature bundles and checksums to release
113+
env:
114+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
71115
run: |
72-
git config user.name "github-actions[bot]"
73-
git config user.email "github-actions[bot]@users.noreply.github.com"
74-
git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
75-
git push origin "${{ steps.version.outputs.tag }}"
116+
gh release upload "${{ steps.version.outputs.tag }}" \
117+
dist/stepsecurity-dev-machine-guard_darwin_amd64.bundle \
118+
dist/stepsecurity-dev-machine-guard_darwin_arm64.bundle \
119+
dist/stepsecurity-dev-machine-guard.sh.bundle \
120+
dist/cosign-checksums.txt \
121+
--clobber
76122
77-
- name: Create GitHub Release
78-
uses: step-security/action-gh-release@d45511d7589f080cf54961ff056b9705a74fd160 # v2.5.0
79-
with:
80-
tag_name: ${{ steps.version.outputs.tag }}
81-
name: ${{ steps.version.outputs.tag }}
82-
generate_release_notes: true
83-
files: |
84-
stepsecurity-dev-machine-guard.sh
85-
stepsecurity-dev-machine-guard.sh.bundle
86-
checksums.txt
123+
- name: Mark release as immutable (not a draft, not a prerelease)
124+
env:
125+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
126+
run: |
127+
gh release edit "${{ steps.version.outputs.tag }}" \
128+
--draft=false \
129+
--prerelease=false \
130+
--latest
87131
88132
- name: Attest build provenance
89133
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
90134
with:
91-
subject-path: stepsecurity-dev-machine-guard.sh
135+
subject-path: |
136+
dist/stepsecurity-dev-machine-guard_darwin_amd64
137+
dist/stepsecurity-dev-machine-guard_darwin_arm64
138+
stepsecurity-dev-machine-guard.sh

.github/workflows/tests.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
lint:
14+
name: Lint
15+
runs-on: macos-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: actions/setup-go@v5
19+
with:
20+
go-version-file: go.mod
21+
- uses: golangci/golangci-lint-action@v6
22+
with:
23+
version: latest
24+
25+
test:
26+
name: Test
27+
runs-on: macos-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
- uses: actions/setup-go@v5
31+
with:
32+
go-version-file: go.mod
33+
- run: make test
34+
35+
smoke:
36+
name: Smoke Tests
37+
runs-on: macos-latest
38+
needs: test
39+
steps:
40+
- uses: actions/checkout@v4
41+
- uses: actions/setup-go@v5
42+
with:
43+
go-version-file: go.mod
44+
- run: make smoke

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,9 @@
1717
!docs/**/*.html
1818
!images/**/*.html
1919

20+
# Go build artifacts
21+
/stepsecurity-dev-machine-guard
22+
dist/
23+
2024
# Temporary files
2125
todo-remove/

.goreleaser.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
version: 2
2+
project_name: stepsecurity-dev-machine-guard
3+
4+
builds:
5+
- id: stepsecurity-dev-machine-guard
6+
main: ./cmd/stepsecurity-dev-machine-guard
7+
binary: stepsecurity-dev-machine-guard
8+
goos:
9+
- darwin
10+
goarch:
11+
- amd64
12+
- arm64
13+
mod_timestamp: "{{ .CommitTimestamp }}"
14+
flags:
15+
- -trimpath
16+
ldflags:
17+
- -s -w
18+
- -X github.com/step-security/dev-machine-guard/internal/buildinfo.GitCommit={{.FullCommit}}
19+
- -X github.com/step-security/dev-machine-guard/internal/buildinfo.ReleaseTag={{.Tag}}
20+
- -X github.com/step-security/dev-machine-guard/internal/buildinfo.ReleaseBranch={{.Branch}}
21+
env:
22+
- CGO_ENABLED=0
23+
24+
archives:
25+
- format: binary
26+
name_template: "{{ .Binary }}_{{ .Os }}_{{ .Arch }}"
27+
28+
checksum:
29+
name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS"
30+
algorithm: sha256
31+
32+
release:
33+
extra_files:
34+
- glob: stepsecurity-dev-machine-guard.sh

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
See [VERSIONING.md](VERSIONING.md) for why the version starts at 1.8.1.
99

10+
## [1.9.0] - 2026-04-03
11+
12+
Migrated from shell script to a compiled Go binary. All existing scanning features, detection logic, CLI flags, output formats, and enterprise telemetry are preserved — this release changes the implementation, not the functionality.
13+
14+
### Added
15+
- **Go binary**: Single compiled binary (`stepsecurity-dev-machine-guard`) replaces the shell script. Zero external dependencies, no runtime required.
16+
- **`configure` / `configure show` commands**: Interactive setup and display of enterprise credentials, search directories, and preferences. Saved to `~/.stepsecurity/config.json`.
17+
1018
## [1.8.2] - 2026-03-17
1119

1220
### Added
@@ -44,5 +52,6 @@ First open-source release. The scanning engine was previously an internal enterp
4452
- Execution log capture and base64 encoding
4553
- Instance locking to prevent concurrent runs
4654

55+
[1.9.0]: https://github.com/step-security/dev-machine-guard/compare/v1.8.2...v1.9.0
4756
[1.8.2]: https://github.com/step-security/dev-machine-guard/compare/v1.8.1...v1.8.2
4857
[1.8.1]: https://github.com/step-security/dev-machine-guard/releases/tag/v1.8.1

CONTRIBUTING.md

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,15 @@ Thank you for your interest in contributing! Dev Machine Guard is an open-source
99
To add detection for a new AI tool, IDE, or framework:
1010

1111
1. Open an issue using the [Feature Request](.github/ISSUE_TEMPLATE/feature_request.yml) template, or
12-
2. Submit a PR modifying `stepsecurity-dev-machine-guard.sh`
12+
2. Submit a PR modifying the appropriate detector in `internal/detector/`
1313

1414
**How to add a new IDE/desktop app:**
1515

16-
Find the `detect_ide_installations()` function and add an entry to the `apps` array:
17-
```bash
18-
"App Name|type_id|Vendor|/Applications/App.app|Contents/MacOS/binary|--version"
19-
```
16+
Find the IDE detector in `internal/detector/ide.go` and add an entry to the apps list. See [Adding Detections](docs/adding-detections.md) for the full guide.
2017

2118
**How to add a new AI CLI tool:**
2219

23-
Find the `detect_ai_cli_tools()` function and add an entry to the `tools` array:
24-
```bash
25-
"tool-name|Vendor|binary1,binary2|~/.config-dir1,~/.config-dir2"
26-
```
20+
Find the AI CLI detector in `internal/detector/ai_cli.go` and add an entry to the tools list. See [Adding Detections](docs/adding-detections.md) for the full guide.
2721

2822
### Improve Documentation
2923

@@ -37,37 +31,37 @@ Documentation lives in the `docs/` folder. Improvements, corrections, and new gu
3731
cd dev-machine-guard
3832
```
3933

40-
2. Make the script executable:
34+
2. Build the binary:
4135
```bash
42-
chmod +x stepsecurity-dev-machine-guard.sh
36+
make build
4337
```
4438

4539
3. Run locally:
4640
```bash
4741
# Pretty output with progress messages
48-
./stepsecurity-dev-machine-guard.sh --verbose
42+
./stepsecurity-dev-machine-guard --verbose
4943

5044
# JSON output
51-
./stepsecurity-dev-machine-guard.sh --json
45+
./stepsecurity-dev-machine-guard --json
5246

5347
# HTML report
54-
./stepsecurity-dev-machine-guard.sh --html report.html
48+
./stepsecurity-dev-machine-guard --html report.html
5549
```
5650

5751
## Code Style
5852

59-
- The script must pass [ShellCheck](https://www.shellcheck.net/) (our CI runs it on every PR)
60-
- Follow the existing code patterns (section headers, function naming, JSON construction)
61-
- Use `print_progress` for status messages (they respect the `--verbose` flag)
62-
- Use `print_error` for error messages (always shown)
53+
- Go source code in `internal/` must pass `golangci-lint` (our CI runs it on every PR)
54+
- Follow the existing code patterns (package structure, naming conventions, JSON struct tags)
55+
- Use the `progress` package for status messages (they respect the `--verbose` flag)
56+
- Use standard Go error handling patterns
6357

6458
## Pull Request Process
6559

6660
1. Fork the repository
6761
2. Create a feature branch (`git checkout -b add-new-tool-detection`)
68-
3. Make your changes
69-
4. Test locally: `./stepsecurity-dev-machine-guard.sh --verbose`
70-
5. Ensure ShellCheck passes: `shellcheck stepsecurity-dev-machine-guard.sh`
62+
3. Edit Go source in `internal/` (not the legacy shell script)
63+
4. Test locally: `./stepsecurity-dev-machine-guard --verbose`
64+
5. Ensure lint and tests pass: `make lint && make test && make smoke`
7165
6. Submit a PR using our [PR template](.github/pull_request_template.md)
7266

7367
## Reporting Issues

0 commit comments

Comments
 (0)