Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for setcap from build command #129

Merged
merged 4 commits into from
Feb 6, 2023
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
19 changes: 13 additions & 6 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ builds:
- s390x
- ppc64le
goarm:
- 5
- 6
- 7
- "5"
- "6"
- "7"
ignore:
- goos: darwin
goarch: arm
Expand All @@ -54,7 +54,7 @@ builds:
goarch: s390x
- goos: freebsd
goarch: arm
goarm: 5
goarm: "5"
flags:
- -trimpath
ldflags:
Expand All @@ -64,8 +64,15 @@ archives:
- format_overrides:
- goos: windows
format: zip
replacements:
darwin: mac
name_template: >-
{{ .ProjectName }}_
{{- .Version }}_
{{- if eq .Os "darwin" }}mac{{ else }}{{ .Os }}{{ end }}_
{{- .Arch }}
{{- with .Arm }}v{{ . }}{{ end }}
{{- with .Mips }}_{{ . }}{{ end }}
{{- if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}

checksum:
algorithm: sha512

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Because the subcommands and flags are constrained to benefit rapid plugin protot
- `CADDY_VERSION` sets the version of Caddy to build.
- `XCADDY_RACE_DETECTOR=1` enables the Go race detector in the build.
- `XCADDY_DEBUG=1` enables the DWARF debug information in the build.
- `XCADDY_SETCAP=1` will run `sudo setcap cap_net_bind_service=+ep` on the temporary binary before running it when in dev mode.
- `XCADDY_SETCAP=1` will run `sudo setcap cap_net_bind_service=+ep` on the resulting binary. By default, the `sudo` command will be used if it is found; set `XCADDY_SUDO=0` to avoid using `sudo` if necessary.
- `XCADDY_SKIP_BUILD=1` causes xcaddy to not compile the program, it is used in conjunction with build tools such as [GoReleaser](https://goreleaser.com). Implies `XCADDY_SKIP_CLEANUP=1`.
- `XCADDY_SKIP_CLEANUP=1` causes xcaddy to leave build artifacts on disk after exiting.
- `XCADDY_WHICH_GO` sets the go command to use when for example more then 1 version of go is installed.
Expand Down
46 changes: 38 additions & 8 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ func runBuild(ctx context.Context, args []string) error {
log.Fatalf("[FATAL] %v", err)
}

// if requested, run setcap to allow binding to low ports
err = setcapIfRequested(output)
if err != nil {
return err
}

// prove the build is working by printing the version
if runtime.GOOS == os.Getenv("GOOS") && runtime.GOARCH == os.Getenv("GOARCH") {
if !filepath.IsAbs(output) {
Expand Down Expand Up @@ -223,14 +229,10 @@ func runDev(ctx context.Context, args []string) error {
return err
}

if os.Getenv("XCADDY_SETCAP") == "1" {
cmd = exec.Command("sudo", "setcap", "cap_net_bind_service=+ep", binOutput)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Printf("[INFO] Setting capabilities (requires admin privileges): %v", cmd.Args)
if err = cmd.Run(); err != nil {
return err
}
// if requested, run setcap to allow binding to low ports
err = setcapIfRequested(binOutput)
if err != nil {
return err
}

log.Printf("[INFO] Running %v\n\n", append([]string{binOutput}, args...))
Expand All @@ -257,6 +259,34 @@ func runDev(ctx context.Context, args []string) error {
return cmd.Wait()
}

func setcapIfRequested(output string) error {
if os.Getenv("XCADDY_SETCAP") != "1" {
return nil
}

args := []string{"setcap", "cap_net_bind_service=+ep", output}

// check if sudo isn't available, or we were instructed not to use it
_, sudoNotFound := exec.LookPath("sudo")
skipSudo := sudoNotFound != nil || os.Getenv("XCADDY_SUDO") == "0"

var cmd *exec.Cmd
if skipSudo {
cmd = exec.Command(args[0], args[1:]...)
} else {
cmd = exec.Command("sudo", args...)
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

log.Printf("[INFO] Setting capabilities (requires admin privileges): %v", cmd.Args)
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to setcap on the binary: %v", err)
}

return nil
}

type module struct {
Path string // module path
Version string // module version
Expand Down