Skip to content

Commit ae4dfe1

Browse files
committed
Use native git-go library
1 parent 276dc81 commit ae4dfe1

File tree

14 files changed

+734
-582
lines changed

14 files changed

+734
-582
lines changed

.ko.yaml

Lines changed: 0 additions & 8 deletions
This file was deleted.

README.md

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,33 @@ The server **cannot** push commands. Ever. That's the point.
4040
## Quick Start
4141

4242
```bash
43-
# Server
44-
./out/gitmdm-server -git [email protected]:org/compliance.git -api-key SECRET
43+
# Server - now with 100% less git CLI dependency!
44+
# Auto-generates a join key from hardware ID if you're too lazy to set one
45+
./gitmdm-server -git /path/to/compliance # Creates repo if it doesn't exist
46+
# or
47+
./gitmdm-server -clone /existing/repo # Uses existing local repo
48+
49+
# The server will display something like:
50+
# ═══════════════════════════════════════════════════════════════
51+
# GitMDM Server Started
52+
# Join Key: 926DD23A5B
53+
#
54+
# To register an agent, run:
55+
# ./gitmdm-agent --server http://localhost:8080 --join 926DD23A5B
56+
# ═══════════════════════════════════════════════════════════════
57+
58+
# Agent - checks in every 20 minutes (because 5 was too clingy)
59+
./gitmdm-agent --server http://localhost:8080 --join 926DD23A5B
60+
```
61+
62+
### Environment Variables (for the Docker crowd)
4563

46-
# Agent
47-
./out/gitmdm-agent -server https://server:8080
64+
```bash
65+
# Server accepts these if you're allergic to flags
66+
export [email protected]:org/compliance.git
67+
export PORT=8080
68+
export JOIN_KEY=SUPERSECRET123 # Or let it auto-generate one
69+
./gitmdm-server
4870
```
4971

5072
## Local Checks
@@ -77,12 +99,16 @@ You'll see output similar to:
7799

78100
SOC 2 compliance evidence in git:
79101
```
80-
devices/laptop-alice/disk_encryption.json ✓
81-
devices/laptop-alice/screen_lock.json ✓
82-
devices/server-prod/firewall.json ✓
102+
devices/
103+
├── 926DD23A5B/ # Hardware IDs, not names (privacy!)
104+
│ ├── info.json # Device metadata
105+
│ ├── disk_encryption.json ✓
106+
│ ├── screen_lock.json ✓
107+
│ └── firewall.json ✓
108+
└── README.md # Auto-created, unlike this one
83109
```
84110

85-
Every check, every change, cryptographically signed and timestamped.
111+
Every check, every change, in git. No database to corrupt, no API to hack.
86112

87113
## Supported Platforms
88114

@@ -102,27 +128,49 @@ Edit, compile, deploy. No runtime configuration files to tamper with.
102128
103129
## Security Guarantees
104130
105-
- Server compromise = read-only access to compliance reports
106-
- No arbitrary code execution, even with root on the server
107-
- Agent decides what runs based on compiled-in checks
108-
- Bash restricted mode when shell execution is needed
131+
- **Server compromise = read-only access to compliance reports** (and they're in git anyway)
132+
- **No arbitrary code execution** - Not even with root on the server
133+
- **Agent decides what runs** - Compiled-in checks, not runtime shenanigans
134+
- **Bash restricted mode** - When we absolutely must shell out
135+
- **No git CLI required** - Pure Go implementation (go-git), works in containers
136+
- **Join key required** - Keeps the riffraff out of your compliance data
109137
110138
## Building
111139
112140
```bash
113141
make all
114142
```
115143

144+
Compiles to static binaries because dynamic linking is for people who enjoy debugging production at 3 AM.
145+
146+
## Code Philosophy
147+
148+
Written in Go, blessed by Rob Pike's simplicity principles:
149+
- Functions read like recipes, not puzzle boxes
150+
- No clever abstractions that require a PhD to understand
151+
- Minimal dependencies (yaml, retry, go-git - that's it!)
152+
- If a function is <7 lines and called once, it's inlined
153+
- Security through simplicity, not complexity theater
154+
116155
## FAQ
117156

118-
**Q: Is this SOC 2 compliant?**
157+
**Q: Is this SOC 2 compliant?**
119158
A: It generates the reports auditors need. Without the backdoors.
120159

121-
**Q: What if we need to change checks?**
160+
**Q: What if we need to change checks?**
122161
A: Rebuild and redeploy. Immutability is a feature, not a bug.
123162

124-
**Q: Why git?**
125-
A: Cryptographic proof, audit trail, existing tooling, no database.
163+
**Q: Why git?**
164+
A: Cryptographic proof, audit trail, existing tooling, no database to "accidentally" DROP.
165+
166+
**Q: Does it need git installed?**
167+
A: Nope! Uses go-git. Works in your hipster minimal container.
168+
169+
**Q: What's a join key?**
170+
A: A speed bump for script kiddies. Not Fort Knox, but keeps honest people honest.
171+
172+
**Q: Why 20-minute check-ins?**
173+
A: Because 5 minutes was needy, and daily was negligent. Goldilocks would approve.
126174

127175
---
128176

cmd/agent/analyzer/auto_login.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ func analyzeGDMAutoLogin(output string) Result {
7373
return Result{Status: statusNA, Description: "Not GDM output"}
7474
}
7575

76-
configFile := getGDMConfigFile(output)
76+
// Determine GDM config file location
77+
configFile := "/etc/gdm3/custom.conf"
78+
if strings.Contains(output, "/etc/gdm/") {
79+
configFile = "/etc/gdm/custom.conf"
80+
}
7781

7882
if strings.Contains(output, "automaticloginenable") {
7983
if strings.Contains(output, "automaticloginenable=true") ||
@@ -187,13 +191,6 @@ func isErrorOutput(output string) bool {
187191
return strings.Contains(output, "does not exist") || strings.Contains(output, "error")
188192
}
189193

190-
func getGDMConfigFile(output string) string {
191-
if strings.Contains(output, "/etc/gdm/") {
192-
return "/etc/gdm/custom.conf"
193-
}
194-
return "/etc/gdm3/custom.conf"
195-
}
196-
197194
func extractGDMAutoLoginUser(output string) string {
198195
if !strings.Contains(output, "automaticlogin=") {
199196
return ""

cmd/agent/executeCommand.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,13 @@ func (*Agent) executeCommandWithPipes(ctx context.Context, checkName, command st
9797
stdoutBytes := stdoutBuf.Bytes()
9898
stdout := string(stdoutBytes)
9999
if len(stdoutBytes) > maxOutputSize {
100-
stdout = string(stdoutBytes[:maxOutputSize]) + "\n[Output truncated to 10KB]..."
100+
stdout = string(stdoutBytes[:maxOutputSize]) + "\n[Output truncated to 90KB]..."
101101
}
102102

103103
stderrBytes := stderrBuf.Bytes()
104104
stderr := string(stderrBytes)
105105
if len(stderrBytes) > maxOutputSize {
106-
stderr = string(stderrBytes[:maxOutputSize]) + "\n[Output truncated to 10KB]..."
106+
stderr = string(stderrBytes[:maxOutputSize]) + "\n[Output truncated to 90KB]..."
107107
}
108108

109109
// Determine exit code

0 commit comments

Comments
 (0)