-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
225 lines (210 loc) · 11.8 KB
/
Copy pathMakefile
File metadata and controls
225 lines (210 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# Windows lacks `ln`, and Go on Windows expects an .exe suffix. Claude Desktop
# on Windows still needs the `databricks-claude-credential-helper.exe` alias
# (the .reg MDM artifact points at it), so on Windows we create a hard link
# via `fsutil hardlink create` — no admin/Developer-Mode required (unlike a
# true symlink). We pin SHELL to cmd.exe on Windows so the recipes work
# regardless of whether the user invokes make from PowerShell, cmd, or Git
# Bash — `rm`/`ln`/`/dev/null` can't be relied on across those.
ifeq ($(OS),Windows_NT)
SHELL := cmd.exe
.SHELLFLAGS := /c
EXE := .exe
DEVNULL := nul
GOPATH_BIN := $(shell go env GOPATH)\bin
# Parens around the `if exist` block are load-bearing: without them, cmd
# parses the following `& fsutil ...` as part of the if's body and skips it
# whenever the alias doesn't already exist (i.e., every fresh build).
LINK_ALIAS = (if exist databricks-claude-credential-helper.exe del /f /q databricks-claude-credential-helper.exe) & fsutil hardlink create databricks-claude-credential-helper.exe databricks-claude.exe
INSTALL_LINK_ALIAS = (if exist "$(GOPATH_BIN)\databricks-claude-credential-helper.exe" del /f /q "$(GOPATH_BIN)\databricks-claude-credential-helper.exe") & fsutil hardlink create "$(GOPATH_BIN)\databricks-claude-credential-helper.exe" "$(GOPATH_BIN)\databricks-claude.exe"
else
EXE :=
DEVNULL := /dev/null
LINK_ALIAS = ln -sf databricks-claude databricks-claude-credential-helper
INSTALL_LINK_ALIAS = ln -sf databricks-claude "$$(go env GOPATH)/bin/databricks-claude-credential-helper"
endif
VERSION ?= $(shell git describe --tags --always --dirty 2>$(DEVNULL) || echo dev)
LDFLAGS := -s -w -X main.Version=$(VERSION)
# Subject identity for `make generate-signing-cert`. Override these for your
# org before rotating into production — admins forking this repo MUST NOT
# leave the defaults in place for a fleet rollout, as the defaults are
# deliberately template-y to avoid impersonating any real organization.
CERT_CN ?= databricks-claude code signing (REPLACE FOR PROD)
CERT_ORG ?= databricks-claude self-signed (REPLACE FOR PROD)
CERT_COUNTRY ?= US
# All launcher binaries, lockstep-versioned (issue #204). The `databricks-agents`
# multiplexer ships alongside the three per-tool binaries (named with the
# `-agents` suffix so it never shadows the Databricks CLI on PATH). Order is
# deterministic (kept explicit rather than a `./cmd/*` glob) so the claude
# alias/.pkg special-casing below stays legible.
BINS := databricks-agents databricks-claude databricks-codex databricks-opencode
# Cross-compile matrix for `dist`: os/arch pairs.
PLATFORMS := darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64 windows/arm64
.DEFAULT_GOAL := build
## Build the databricks-claude binary (and the credential-helper alias that
## the Claude Desktop MDM artifacts expect — symlink on Unix, hard link on
## Windows) plus the databricks-codex and databricks-opencode binaries. codex
## and opencode have no credential-helper surface, so they get a plain
## `go build` with no alias step. The `databricks-agents` multiplexer dispatches
## to the three per-tool binaries and is cross-compiled alongside them by `dist`.
build:
go build -ldflags="$(LDFLAGS)" -o databricks-claude$(EXE) ./cmd/databricks-claude
$(LINK_ALIAS)
go build -ldflags="$(LDFLAGS)" -o databricks-codex$(EXE) ./cmd/databricks-codex
go build -ldflags="$(LDFLAGS)" -o databricks-opencode$(EXE) ./cmd/databricks-opencode
go build -ldflags="$(LDFLAGS)" -o databricks-agents$(EXE) ./cmd/databricks-agents
## Install to GOPATH/bin (also drops the credential-helper alias so Claude
## Desktop's inferenceCredentialHelper can target a stable path). codex
## installs plainly — no alias, no Desktop/MDM surface.
install:
go install -ldflags="$(LDFLAGS)" ./cmd/databricks-claude
$(INSTALL_LINK_ALIAS)
go install -ldflags="$(LDFLAGS)" ./cmd/databricks-codex
go install -ldflags="$(LDFLAGS)" ./cmd/databricks-opencode
go install -ldflags="$(LDFLAGS)" ./cmd/databricks-agents
## Run tests with verbose output
test:
go test ./... -v
## Cross-compile every launcher in $(BINS) — the `databricks-agents` multiplexer plus
## databricks-claude/-codex/-opencode — for linux/darwin/windows amd64 + arm64
## (24 artifacts, lockstep-versioned per issue #204). Symlinks for the
## credential-helper alias are NOT generated here — packagers (brew, .pkg,
## .deb) are responsible for creating them at install time pointing at a
## predictable system path. codex, opencode, and the multiplexer have no
## credential-helper alias and no .pkg/MDM surface (all CLI-only).
##
## Implemented as a shell `for` loop with `set -e` (NOT a make `$(foreach)`,
## which would collapse all builds onto one recipe line whose exit status is
## only the last command's — silently masking a mid-loop build failure and
## shipping a partial artifact set). `set -e` restores fail-fast so a red
## build fails the release. IMPORTANT: the loop MUST stay a single
## backslash-continued logical line so `set -e` governs one shell invocation;
## breaking the continuations would make `set -e` per-line and reopen the
## partial-release hazard. This target is Unix-only by construction — the shell
## `for`/`set -e`/`$${p%/*}` syntax and `mkdir -p` can't run under the Windows
## `cmd.exe` SHELL — and only runs on ubuntu CI runners.
dist:
mkdir -p dist
set -e; for bin in $(BINS); do \
for p in $(PLATFORMS); do \
os=$${p%/*}; arch=$${p#*/}; ext=; \
if [ "$$os" = windows ]; then ext=.exe; fi; \
echo "building $$bin $$os/$$arch"; \
GOOS=$$os GOARCH=$$arch go build -ldflags="$(LDFLAGS)" -o dist/$$bin-$$os-$$arch$$ext ./cmd/$$bin; \
done; \
done
## Build a universal2 macOS .pkg installer. Set APPLE_INTERNAL_SIGNING_IDENTITY
## to codesign the binary inside the pkg with hardened-runtime flags; otherwise
## the binary is ad-hoc signed. The .pkg itself is always unsigned — productsign
## requires an Apple-issued installer cert, which a self-signed cert can't satisfy.
pkg:
rm -rf build root scripts/postinstall dist/databricks-claude*.pkg
mkdir -p build dist scripts root/usr/local/bin
GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o dist/databricks-claude-darwin-arm64 ./cmd/databricks-claude
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="$(LDFLAGS)" -o dist/databricks-claude-darwin-amd64 ./cmd/databricks-claude
lipo -create -output build/databricks-claude dist/databricks-claude-darwin-arm64 dist/databricks-claude-darwin-amd64
@if [ -n "$$APPLE_INTERNAL_SIGNING_IDENTITY" ]; then \
echo "Signing binary with identity: $$APPLE_INTERNAL_SIGNING_IDENTITY"; \
codesign --force --options runtime --timestamp --sign "$$APPLE_INTERNAL_SIGNING_IDENTITY" build/databricks-claude; \
else \
echo "APPLE_INTERNAL_SIGNING_IDENTITY unset — ad-hoc signing"; \
codesign --force --options runtime --sign - build/databricks-claude; \
fi
cp build/databricks-claude root/usr/local/bin/databricks-claude
ln -sf databricks-claude root/usr/local/bin/databricks-claude-credential-helper
printf '#!/bin/sh\nset -e\ncd /usr/local/bin\nln -sf databricks-claude databricks-claude-credential-helper\n' > scripts/postinstall
chmod +x scripts/postinstall
pkgbuild --root root --scripts scripts \
--identifier com.databricks.databricks-claude \
--version "$(VERSION)" \
--install-location / \
dist/databricks-claude-component.pkg
productbuild --package dist/databricks-claude-component.pkg \
--identifier com.databricks.databricks-claude.dist \
--version "$(VERSION)" \
dist/databricks-claude.pkg
rm -f dist/databricks-claude-component.pkg
@echo "Built dist/databricks-claude.pkg"
## Emit the MDM trust profile (.mobileconfig) that establishes the signing cert
## as a trusted root for code-signing on managed Macs. Requires
## dist/signing-cert.pem (run `make generate-signing-cert` first).
trust-profile: build
./databricks-claude desktop generate-trust-profile \
--cert dist/signing-cert.pem \
--output dist/databricks-claude-trust.mobileconfig
## Generate a 5-year self-signed code-signing cert for the .pkg. Run once;
## paste the printed values into GitHub repo secrets. Rotate ≥60 days before
## expiry (see README rotation runbook).
generate-signing-cert:
mkdir -p dist
@if [ -z "$$P12_PASSWORD" ]; then \
echo "ERROR: set P12_PASSWORD env var (a strong random password)"; \
exit 1; \
fi
@if [ -f dist/signing-cert.key ]; then \
echo "ERROR: dist/signing-cert.key already exists. Refusing to overwrite."; \
echo " Move/archive the existing key first if you intend to rotate."; \
exit 1; \
fi
@echo "Generating cert with subject:"
@echo " CN=$(CERT_CN)"
@echo " O=$(CERT_ORG)"
@echo " C=$(CERT_COUNTRY)"
@case "$(CERT_CN)$(CERT_ORG)" in *"REPLACE FOR PROD"*) \
echo ""; \
echo "WARNING: cert subject contains the placeholder 'REPLACE FOR PROD'."; \
echo " For a real fleet rollout, override CERT_CN, CERT_ORG, and"; \
echo " CERT_COUNTRY to your org's identity. Continuing in 3s — Ctrl-C to abort."; \
sleep 3 ;; \
esac
openssl req -x509 -newkey rsa:2048 -days 1825 -nodes \
-subj "/CN=$(CERT_CN)/O=$(CERT_ORG)/C=$(CERT_COUNTRY)" \
-addext "keyUsage=critical,digitalSignature" \
-addext "extendedKeyUsage=codeSigning,1.2.840.113635.100.4.13" \
-keyout dist/signing-cert.key -out dist/signing-cert.pem
openssl pkcs12 -export -legacy -out dist/signing-cert.p12 \
-inkey dist/signing-cert.key -in dist/signing-cert.pem \
-passout pass:"$$P12_PASSWORD"
base64 -i dist/signing-cert.p12 -o dist/signing-cert.p12.b64
@echo
@echo "Cert generated. Paste the following into GitHub repo secrets:"
@echo " APPLE_INTERNAL_SIGNING_P12_BASE64 = (contents of dist/signing-cert.p12.b64)"
@echo " APPLE_INTERNAL_SIGNING_P12_PASSWORD = (the value of P12_PASSWORD)"
@echo " APPLE_INTERNAL_SIGNING_IDENTITY = $(CERT_CN)"
@echo " APPLE_INTERNAL_SIGNING_CERT_PEM = (contents of dist/signing-cert.pem)"
@echo
@echo "Rotate this cert >=60 days before expiry."
## Remove build artifacts
clean:
rm -f databricks-claude databricks-claude-credential-helper databricks-codex databricks-opencode databricks-agents$(EXE)
rm -rf dist/ build/ root/ scripts/postinstall
## Run go vet
lint:
go vet ./...
## STUB for adopters: notarize a self-built macOS binary for fleet rollout.
## Upstream databricks-claude ships UNSIGNED — signing/notarization is the
## deployer's responsibility (see issue #54 and the README "Signing
## prerequisite" section). This target documents the contract so adopters who
## fork the repo can fill it in for their org. It is intentionally NOT wired
## end-to-end upstream.
##
## Expected env when implemented:
## DEVELOPER_ID_APPLICATION -- e.g. "Developer ID Application: Your Org (TEAMID)"
## NOTARYTOOL_PROFILE -- an `xcrun notarytool store-credentials` keychain profile
##
## Expected sequence (codesign -> notarize -> staple):
## codesign --force --options runtime --timestamp \
## --sign "$$DEVELOPER_ID_APPLICATION" build/databricks-claude
## ditto -c -k --keepParent build/databricks-claude build/databricks-claude.zip
## xcrun notarytool submit build/databricks-claude.zip \
## --keychain-profile "$$NOTARYTOOL_PROFILE" --wait
## xcrun stapler staple build/databricks-claude # (or staple the .pkg / .dmg)
notarize:
@echo "make notarize: STUB — upstream databricks-claude ships unsigned."
@echo " Signing/notarization is an adopter responsibility (see issue #54"
@echo " and the README 'Signing prerequisite' section)."
@echo ""
@echo " To implement for your org: fork the repo, set DEVELOPER_ID_APPLICATION"
@echo " and NOTARYTOOL_PROFILE, and fill in the codesign -> notarytool -> stapler"
@echo " sequence documented in the Makefile recipe comment above this target."
@exit 1
.PHONY: build install test dist clean lint pkg trust-profile generate-signing-cert notarize