Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ body:
- type: input
id: version
attributes:
label: Script Version
description: "Run: ./stepsecurity-dev-machine-guard.sh --version"
placeholder: "1.8.1"
label: Version
description: "Run: ./stepsecurity-dev-machine-guard --version"
placeholder: "1.9.0"
validations:
required: true
- type: input
Expand All @@ -28,7 +28,7 @@ body:
attributes:
label: Command Run
description: The exact command you ran
placeholder: "./stepsecurity-dev-machine-guard.sh --json"
placeholder: "./stepsecurity-dev-machine-guard --json"
validations:
required: true
- type: textarea
Expand Down
7 changes: 4 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
## Testing

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

## Related Issues

Expand Down
121 changes: 84 additions & 37 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ jobs:
release:
name: Build, Sign & Release
runs-on: ubuntu-latest
environment: release
permissions:
contents: write # create tag, release, and upload assets
id-token: write # Sigstore OIDC keyless signing
attestations: write # SLSA build provenance
contents: write # create tag, release, and upload assets
id-token: write # OIDC token for cosign keyless signing and build provenance
attestations: write # SLSA build provenance

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

- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Extract version from script
- name: Extract version from source
id: version
run: |
version=$(grep -m1 '^AGENT_VERSION=' stepsecurity-dev-machine-guard.sh | sed 's/AGENT_VERSION="//;s/"//')
version=$(grep -m1 'Version.*=' internal/buildinfo/version.go | sed 's/.*"\(.*\)".*/\1/')
if [ -z "$version" ]; then
echo "::error::Could not extract AGENT_VERSION from script"
echo "::error::Could not extract Version from internal/buildinfo/version.go"
exit 1
fi
tag="v${version}"
Expand All @@ -40,52 +41,98 @@ jobs:
- name: Check tag does not already exist
run: |
if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
echo "::error::Tag ${{ steps.version.outputs.tag }} already exists. Bump AGENT_VERSION in the script before releasing."
echo "::error::Tag ${{ steps.version.outputs.tag }} already exists. Bump Version in internal/buildinfo/version.go before releasing."
exit 1
fi

- name: Create tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Install cosign
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0

- name: Sign script with Sigstore (keyless)
- name: Prepare release artifacts for signing
run: |
cosign sign-blob stepsecurity-dev-machine-guard.sh \
--bundle stepsecurity-dev-machine-guard.sh.bundle \
--yes
# Copy binaries to match the exact names users download from the release.
# GoReleaser uploads as name_template (e.g. stepsecurity-dev-machine-guard_darwin_amd64)
# but keeps them in build subdirs locally. We copy to dist/ with release names
# so cosign signs the same bytes users verify against.
AMD64_SRC=$(find dist -type f -name 'stepsecurity-dev-machine-guard' -path '*darwin_amd64*' | head -1)
ARM64_SRC=$(find dist -type f -name 'stepsecurity-dev-machine-guard' -path '*darwin_arm64*' | head -1)

- name: Verify signature
for label in "amd64:${AMD64_SRC}" "arm64:${ARM64_SRC}"; do
name="${label%%:*}"
path="${label#*:}"
if [ -z "$path" ] || [ ! -f "$path" ]; then
echo "::error::Binary not found for ${name}"
find dist -type f
exit 1
fi
done

cp "$AMD64_SRC" dist/stepsecurity-dev-machine-guard_darwin_amd64
cp "$ARM64_SRC" dist/stepsecurity-dev-machine-guard_darwin_arm64
echo "Prepared release artifacts for signing"

- name: Sign artifacts with Sigstore (keyless)
run: |
cosign verify-blob stepsecurity-dev-machine-guard.sh \
--bundle stepsecurity-dev-machine-guard.sh.bundle \
--certificate-identity-regexp "github.com/step-security/dev-machine-guard" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
cosign sign-blob dist/stepsecurity-dev-machine-guard_darwin_amd64 \
--bundle dist/stepsecurity-dev-machine-guard_darwin_amd64.bundle --yes
cosign sign-blob dist/stepsecurity-dev-machine-guard_darwin_arm64 \
--bundle dist/stepsecurity-dev-machine-guard_darwin_arm64.bundle --yes
cosign sign-blob stepsecurity-dev-machine-guard.sh \
--bundle dist/stepsecurity-dev-machine-guard.sh.bundle --yes

- name: Generate checksums
run: |
sha256sum stepsecurity-dev-machine-guard.sh > checksums.txt
sha256sum stepsecurity-dev-machine-guard.sh.bundle >> checksums.txt
echo "Checksums:"
cat checksums.txt
# Separate checksum file for cosign-signed artifacts (script + bundles).
# GoReleaser already generates checksums for the Go binaries in its own SHA256SUMS file.
sha256sum dist/stepsecurity-dev-machine-guard_darwin_amd64 > dist/cosign-checksums.txt
sha256sum dist/stepsecurity-dev-machine-guard_darwin_arm64 >> dist/cosign-checksums.txt
sha256sum stepsecurity-dev-machine-guard.sh >> dist/cosign-checksums.txt

- name: Create tag
- name: Upload signature bundles and checksums to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"
gh release upload "${{ steps.version.outputs.tag }}" \
dist/stepsecurity-dev-machine-guard_darwin_amd64.bundle \
dist/stepsecurity-dev-machine-guard_darwin_arm64.bundle \
dist/stepsecurity-dev-machine-guard.sh.bundle \
dist/cosign-checksums.txt \
--clobber

- name: Create GitHub Release
uses: step-security/action-gh-release@d45511d7589f080cf54961ff056b9705a74fd160 # v2.5.0
with:
tag_name: ${{ steps.version.outputs.tag }}
name: ${{ steps.version.outputs.tag }}
generate_release_notes: true
files: |
stepsecurity-dev-machine-guard.sh
stepsecurity-dev-machine-guard.sh.bundle
checksums.txt
- name: Mark release as immutable (not a draft, not a prerelease)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release edit "${{ steps.version.outputs.tag }}" \
--draft=false \
--prerelease=false \
--latest

- name: Attest build provenance
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: stepsecurity-dev-machine-guard.sh
subject-path: |
dist/stepsecurity-dev-machine-guard_darwin_amd64
dist/stepsecurity-dev-machine-guard_darwin_arm64
stepsecurity-dev-machine-guard.sh
44 changes: 44 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
lint:
name: Lint
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@v6
with:
version: latest

test:
name: Test
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: make test

smoke:
name: Smoke Tests
runs-on: macos-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: make smoke
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@
!docs/**/*.html
!images/**/*.html

# Go build artifacts
/stepsecurity-dev-machine-guard
dist/

# Temporary files
todo-remove/
34 changes: 34 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2
project_name: stepsecurity-dev-machine-guard

builds:
- id: stepsecurity-dev-machine-guard
main: ./cmd/stepsecurity-dev-machine-guard
binary: stepsecurity-dev-machine-guard
goos:
- darwin
goarch:
- amd64
- arm64
mod_timestamp: "{{ .CommitTimestamp }}"
flags:
- -trimpath
ldflags:
- -s -w
- -X github.com/step-security/dev-machine-guard/internal/buildinfo.GitCommit={{.FullCommit}}
- -X github.com/step-security/dev-machine-guard/internal/buildinfo.ReleaseTag={{.Tag}}
- -X github.com/step-security/dev-machine-guard/internal/buildinfo.ReleaseBranch={{.Branch}}
env:
- CGO_ENABLED=0

archives:
- format: binary
name_template: "{{ .Binary }}_{{ .Os }}_{{ .Arch }}"

checksum:
name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS"
algorithm: sha256

release:
extra_files:
- glob: stepsecurity-dev-machine-guard.sh
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

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

## [1.9.0] - 2026-04-03

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.

### Added
- **Go binary**: Single compiled binary (`stepsecurity-dev-machine-guard`) replaces the shell script. Zero external dependencies, no runtime required.
- **`configure` / `configure show` commands**: Interactive setup and display of enterprise credentials, search directories, and preferences. Saved to `~/.stepsecurity/config.json`.

## [1.8.2] - 2026-03-17

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

[1.9.0]: https://github.com/step-security/dev-machine-guard/compare/v1.8.2...v1.9.0
[1.8.2]: https://github.com/step-security/dev-machine-guard/compare/v1.8.1...v1.8.2
[1.8.1]: https://github.com/step-security/dev-machine-guard/releases/tag/v1.8.1
36 changes: 15 additions & 21 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,15 @@ Thank you for your interest in contributing! Dev Machine Guard is an open-source
To add detection for a new AI tool, IDE, or framework:

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

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

Find the `detect_ide_installations()` function and add an entry to the `apps` array:
```bash
"App Name|type_id|Vendor|/Applications/App.app|Contents/MacOS/binary|--version"
```
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.

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

Find the `detect_ai_cli_tools()` function and add an entry to the `tools` array:
```bash
"tool-name|Vendor|binary1,binary2|~/.config-dir1,~/.config-dir2"
```
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.

### Improve Documentation

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

2. Make the script executable:
2. Build the binary:
```bash
chmod +x stepsecurity-dev-machine-guard.sh
make build
```

3. Run locally:
```bash
# Pretty output with progress messages
./stepsecurity-dev-machine-guard.sh --verbose
./stepsecurity-dev-machine-guard --verbose

# JSON output
./stepsecurity-dev-machine-guard.sh --json
./stepsecurity-dev-machine-guard --json

# HTML report
./stepsecurity-dev-machine-guard.sh --html report.html
./stepsecurity-dev-machine-guard --html report.html
```

## Code Style

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

## Pull Request Process

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

## Reporting Issues
Expand Down
Loading
Loading