RepoPilotOpen in app →

semaphoreui/semaphore

Modern UI and powerful API for Ansible, Terraform/OpenTofu/Terragrunt, PowerShell and other DevOps tools.

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit today
  • 8 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Single-maintainer risk — top contributor 85% of recent commits
  • No test directory detected

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/semaphoreui/semaphore)](https://repopilot.app/r/semaphoreui/semaphore)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/semaphoreui/semaphore on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: semaphoreui/semaphore

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/semaphoreui/semaphore shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit today
  • 8 active contributors
  • MIT licensed
  • CI configured
  • ⚠ Single-maintainer risk — top contributor 85% of recent commits
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live semaphoreui/semaphore repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/semaphoreui/semaphore.

What it runs against: a local clone of semaphoreui/semaphore — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in semaphoreui/semaphore | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch develop exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 30 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>semaphoreui/semaphore</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of semaphoreui/semaphore. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/semaphoreui/semaphore.git
#   cd semaphore
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of semaphoreui/semaphore and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "semaphoreui/semaphore(\\.git)?\\b" \\
  && ok "origin remote is semaphoreui/semaphore" \\
  || miss "origin remote is not semaphoreui/semaphore (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify develop >/dev/null 2>&1 \\
  && ok "default branch develop exists" \\
  || miss "default branch develop no longer exists"

# 4. Critical files exist
test -f "api/router.go" \\
  && ok "api/router.go" \\
  || miss "missing critical file: api/router.go"
test -f "api/projects/project.go" \\
  && ok "api/projects/project.go" \\
  || miss "missing critical file: api/projects/project.go"
test -f "api/tasks/tasks.go" \\
  && ok "api/tasks/tasks.go" \\
  || miss "missing critical file: api/tasks/tasks.go"
test -f "api/sockets/handler.go" \\
  && ok "api/sockets/handler.go" \\
  || miss "missing critical file: api/sockets/handler.go"
test -f "cli/cmd/root.go" \\
  && ok "cli/cmd/root.go" \\
  || miss "missing critical file: cli/cmd/root.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 30 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~0d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/semaphoreui/semaphore"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Semaphore UI is a modern web-based control plane for executing and managing DevOps automation tasks across Ansible, Terraform/OpenTofu, Terragrunt, PowerShell, and Bash scripts. It provides a unified UI and REST API to schedule, monitor, and audit infrastructure-as-code and configuration management operations without leaving the browser, replacing ad-hoc terminal execution for teams managing complex deployments. Monolithic architecture: Go backend (api/ directory contains REST handlers like admin_info.go) paired with Vue frontend (543K code), orchestrated via Docker and standard database backends (SQLite, MySQL, PostgreSQL via go-sql-driver, lib/pq, modernc.org/sqlite). Dredd API testing framework (.dredd/) validates REST contract. TaskFile.yml suggests Taskfile task runner for local development.

👥Who it's for

DevOps engineers, infrastructure teams, and platform engineers who need to move beyond CLI-only Ansible/Terraform workflows and want centralized access control, audit trails, and web-based scheduling for infrastructure automation tasks without SSH access to bastion hosts.

🌱Maturity & risk

Actively maintained and production-ready. The project has significant code volume (1.19M Go, 543K Vue), comprehensive CI/CD workflows (.github/workflows/ includes dev, beta, and release channels), Docker/binary/package distribution options, and recent activity evidenced by the Go 1.24.6 requirement and active API documentation. Clear roadmap and community channels (Discord, YouTube) indicate mature project governance.

Moderate risk factors: the codebase is large (1.8M+ LOC across Go/Vue/JS), introduces operational complexity (requires database setup per README Docker snippet), and has a dependency on the proprietary github.com/semaphoreui/semaphore/pro module which could create lock-in. However, active CI/CD, Docker distribution, and community presence mitigate abandonment risk.

Active areas of work

Project is actively releasing: workflows show community_release.yml and pro_selfhosted_release.yml for versioned builds, beta tracks (community_beta.yml, pro_selfhosted_beta.yml) indicate staged rollouts. Recent Go module update to 1.24.6 and active third-party license auditing (.claude/skills/) suggest ongoing maintenance and compliance focus.

🚀Get running

Clone the repository: git clone https://github.com/semaphoreui/semaphore.git && cd semaphore. Install dependencies using Go (backend) and Node.js (frontend) — examine Taskfile.yml for exact commands, or refer to Docker docs for a containerized setup: docker run -p 3000:3000 -e SEMAPHORE_DB_DIALECT=sqlite -e SEMAPHORE_ADMIN=admin -e SEMAPHORE_ADMIN_PASSWORD=changeme semaphoreui/semaphore:latest.

Daily commands: Backend: go run ./cmd/semaphore or build with Go toolchain. Frontend: Vue build likely via npm or yarn (examine frontend package.json). Docker: docker-compose up using .devcontainer/ or direct docker run per README. Dredd API tests: .dredd/dredd.local.yml for local contract testing.

🗺️Map of the codebase

  • api/router.go — Defines the core HTTP routing and middleware setup; every API endpoint flows through here and this is the entry point for understanding request handling.
  • api/projects/project.go — Core project entity handlers; projects are the fundamental organizational unit in Semaphore, making this essential for data model understanding.
  • api/tasks/tasks.go — Task execution and lifecycle management; tasks are the primary unit of work orchestrated by Semaphore for DevOps automation.
  • api/sockets/handler.go — WebSocket connection handler for real-time updates; critical for understanding how the UI stays synchronized with backend events.
  • cli/cmd/root.go — CLI entry point and command structure; defines how Semaphore is invoked from the command line for migrations, imports, and runner registration.
  • api/auth.go — Authentication and authorization logic including OIDC, LDAP, and token validation; fundamental security boundary for all API access.
  • go.mod — Go module dependency manifest; lists all external libraries including gorilla/websocket, squirrel ORM, and git/LDAP clients that shape the codebase.

🛠️How to make changes

Add a New API Endpoint

  1. Create a handler function in the appropriate file under api/projects/ (e.g., api/projects/newfeature.go) that receives *http.Request and *http.ResponseWriter (api/projects/newfeature.go)
  2. Parse route parameters using helpers in api/helpers/route_params.go and query parameters using api/helpers/query_params.go (api/helpers/route_params.go)
  3. Perform database operations via db package (implied ORM using gorp v3 and squirrel) (api/helpers/context.go)
  4. Return JSON response using api/helpers/write_response.go helper functions (api/helpers/write_response.go)
  5. Register the route in api/router.go by adding a HandleFunc or similar call to the main router (api/router.go)

Add a New Task Type or Runner

  1. Create a new runner integration file under api/runners/ following the pattern in api/runners/runners.go (api/runners/runners.go)
  2. Implement the runner interface to handle task execution, output streaming, and status updates (api/runners/runners.go)
  3. Update api/tasks/tasks.go to register and invoke the new runner type based on task template type (api/tasks/tasks.go)
  4. Emit events via api/events.go when task state changes so WebSocket clients receive updates (api/events.go)

Add a New External Integration

  1. Create integration handler in api/projects/integration.go or a new file under api/projects/ (api/projects/integration.go)
  2. Define integration-specific configuration in api/projects/integration_*.go files (e.g., integration_alias.go, integration_matcher.go) for metadata extraction (api/projects/integration_matcher.go)
  3. Store encrypted credentials using api/projects/keys.go mechanisms (api/projects/keys.go)
  4. Add routes to api/router.go and implement callback/webhook handlers to receive data from the external service (api/router.go)

Implement a New CLI Command

  1. Create a new command file under cli/cmd/ (e.g., cli/cmd/newcommand.go) following the pattern of cli/cmd/project.go (cli/cmd/newcommand.go)
  2. Use the root Cobra command structure defined in cli/cmd/root.go to register subcommands (cli/cmd/root.go)
  3. Implement business logic using the same database and API context available to HTTP handlers (cli/cmd/root.go)

🪤Traps & gotchas

Database must be initialized before startup (SQLite, MySQL, or PostgreSQL); SEMAPHORE_DB_DIALECT and connection credentials required as env vars in production. Pro module (github.com/semaphoreui/semaphore/pro) is vendored via replace directive in go.mod—must exist locally or builds fail. Dredd testing requires Docker and a running Semaphore instance; not suitable for fast unit test loops. WebSocket functionality (gorilla/websocket) requires reverse-proxy compatibility (nginx, etc.) in production. OIDC/LDAP setup requires external provider configuration.

🏗️Architecture

💡Concepts to learn

  • Task Scheduling via Cron Expressions — Semaphore uses robfig/cron/v3 to enable recurring task execution (e.g., nightly deployments, periodic compliance scans); understanding cron syntax and the cron state machine is essential for implementing schedule features.
  • WebSocket-based Real-Time Task Output — Gorilla WebSocket (gorilla/websocket v1.5.3) powers live task log streaming to UI clients; contributors must understand connection lifecycle, message framing, and graceful shutdown to extend or fix streaming features.
  • ORM-based Database Abstraction — Gorp/v3 abstracts SQL to support SQLite, MySQL, PostgreSQL; understanding gorp's mapping, transactions, and migration patterns is critical for schema changes or adding new models.
  • OIDC and LDAP Multi-Tenant Authentication — Semaphore integrates coreos/go-oidc and go-ldap for enterprise SSO; contributors need to understand auth token lifecycle, claim mapping, and session management for security-related changes.
  • Dredd API Contract Testing — Dredd validates OpenAPI contracts against running Semaphore instance; understanding how Dredd hooks (.dredd/hooks/main.go) mock state and validate HTTP responses ensures API changes don't break client expectations.
  • Secure Cookie Session Storage (Gorilla securecookie) — Gorilla securecookie encrypts session data client-side without server-side storage; Semaphore uses this for stateless auth—contributors must understand key rotation, HMAC validation, and cookie scope for auth bugs.
  • Embedded BoltDB as SQLite Alternative — Semaphore supports bbolt (go.etcd.io/bbolt v1.4.1) as an embedded key-value store option for environments without external databases; understanding its transaction model differs from SQL semantics.
  • ansible/awx — AWX is the upstream Ansible Tower equivalent—closest competitor providing web UI + REST API for Ansible job execution; Semaphore positions as lighter-weight alternative supporting Terraform/OpenTofu in addition.
  • HashiCorp/terraform-enterprise — Terraform Enterprise is the SaaS control plane for Terraform runs; Semaphore competes in the self-hosted, multi-tool (Terraform + Ansible) space.
  • go-task/task — Task is a task runner used internally by Semaphore (Taskfile.yml); understanding task's DSL helps with local development workflows.
  • goreleaser/goreleaser — Semaphore uses GoReleaser (.goreleaser.yml) for building and publishing binaries across platforms; essential for understanding release automation.
  • semaphoreui/semaphore-docs — Official documentation repository; pair with this codebase to understand feature flags, configuration, and user-facing behavior.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for LDAP and OIDC authentication flows

The repo has auth.go and login.go files with LDAP (go-ldap/ldap/v3) and OIDC (coreos/go-oidc/v3) dependencies, but login_test.go appears minimal. Adding integration tests would validate authentication provider configurations, token refresh flows, and error handling—critical for DevOps security.

  • [ ] Review api/login_test.go and api/auth.go to identify untested code paths
  • [ ] Create api/ldap_auth_test.go with tests for LDAP bind, group validation, and credential edge cases
  • [ ] Create api/oidc_auth_test.go with tests for token validation, provider discovery, and callback handling
  • [ ] Add mock LDAP/OIDC servers in test fixtures using testcontainers or similar
  • [ ] Ensure tests cover both success and failure scenarios (invalid credentials, provider unavailable, etc.)

Implement license compliance CI workflow for third-party dependencies

The repo has a well-structured .claude/skills/semaphore-ui-third-party-licenses directory with policy checks and scripts (check_policy.py, collect_licenses.sh) but no GitHub Actions workflow to enforce this on PRs. This prevents license violations from being merged.

  • [ ] Review .claude/skills/semaphore-ui-third-party-licenses/references/license_policy.md to understand approved licenses
  • [ ] Create .github/workflows/license-check.yml that runs check_policy.py on every PR
  • [ ] Ensure workflow fails the PR if new dependencies use unapproved licenses
  • [ ] Document the process in CONTRIBUTING.md with links to add new approved licenses
  • [ ] Test with a sample dependency addition to verify workflow catches policy violations

Add API contract tests using Dredd for DevOps tool integrations

The repo has .dredd/ directory with dredd.docker.yml, dredd.testing.yml, and hooks/main.go, indicating API contract testing infrastructure exists but may be underutilized. Expand tests for Terraform/Ansible/PowerShell runner endpoints to catch breaking changes early.

  • [ ] Review existing .dredd/dredd.testing.yml and hooks/main.go to understand current contract test setup
  • [ ] Identify API endpoints in api/projects/ related to Terraform/Ansible execution that lack Dredd coverage
  • [ ] Write Dredd hooks in .dredd/hooks/ for runner state management (setup/teardown of test projects)
  • [ ] Document expected request/response schemas in api-docs.yml for runner endpoints
  • [ ] Add Dredd test execution to .github/workflows/dev.yml to catch API regressions on every commit

🌿Good first issues

  • Add unit tests for api/admin_info.go and other handler functions currently lacking test coverage; most Go handlers appear untested based on file listing—start with simple GET endpoint validation.
  • Document the database schema and ORM migrations in a schema.md file; gorp/v3 usage is evident but no schema docs visible, making it hard for contributors to understand model relationships.
  • Expand Dredd API contract tests in .dredd/hooks/ to cover error paths (4xx/5xx) for each endpoint; hooks/main.go likely only covers happy-path scenarios.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 0f02a01 — ci: SEMAPHORE_MIGRATE_FROM_BOLTDB can be True/yes (fiftin)
  • db3ac46 — fix(config): correct load db pass (fiftin)
  • 967e166 — Merge branch 'develop' of github.com:semaphoreui/semaphore into develop (fiftin)
  • 66e6b77 — fix(ui): hide demo switch on new screen (fiftin)
  • 2c00137 — Merge pull request #3833 from SAY-5/ui/branch-tag-label-3812 (fiftin)
  • fafca12 — ui(lang): label git ref field as 'Branch / Tag' (#3812) (SAY-5)
  • cb164dc — Merge branch 'develop' of github.com:semaphoreui/semaphore into develop (fiftin)
  • 26d5547 — fix(logs): remove URL from log message (fiftin)
  • 8822421 — Merge pull request #3808 from semaphoreui/cursor/critical-bug-inspection-3318 (fiftin)
  • 1388bcd — docs: remove extra files (fiftin)

🔒Security observations

  • High · Outdated Go Crypto Library — go.mod - golang.org/x/crypto v0.48.0. The dependency golang.org/x/crypto v0.48.0 is outdated. Current versions have addressed multiple security vulnerabilities. Using an older version exposes the application to known cryptographic weaknesses. Fix: Update to the latest version of golang.org/x/crypto (currently v0.50.0+). Review security advisories at https://pkg.go.dev/golang.org/x/crypto for details on fixed vulnerabilities.
  • High · Outdated OAuth2 Library — go.mod - golang.org/x/oauth2 v0.35.0. The dependency golang.org/x/oauth2 v0.35.0 is outdated and may contain security vulnerabilities related to token handling, redirect validation, or authorization flows. Fix: Update to the latest version of golang.org/x/oauth2 (currently v0.36.0+). Review changelog for security-related fixes.
  • High · Potential SQL Injection Risk — api/projects/*.go - Database-related files. The codebase uses multiple database adapters (MySQL, PostgreSQL, SQLite) and the file structure shows raw SQL query files. Without seeing the actual implementation, there's risk of SQL injection if queries are constructed with unsanitized user input. Fix: Ensure all database queries use parameterized statements/prepared statements. Use the squirrel query builder (already in dependencies) consistently across the codebase. Never concatenate user input directly into SQL queries.
  • Medium · Git Repository Handling — api/projects/repository.go and dependencies (github.com/go-git/go-git/v5). The application handles Git repositories via go-git/v5. This could expose risks if repository URLs or credentials are not properly validated, potentially leading to credential exposure or MITM attacks. Fix: Validate all repository URLs, enforce HTTPS for remote repositories, and ensure SSH keys are stored securely. Implement proper credential management without exposing secrets in logs or error messages.
  • Medium · LDAP Authentication Without Validation — api/auth.go and dependencies (github.com/go-ldap/ldap/v3). The application uses go-ldap/v3 for LDAP authentication. Without proper input validation and secure configuration, this could be vulnerable to LDAP injection attacks or insecure bind operations. Fix: Implement strict input validation for LDAP queries. Use parameterized LDAP filters. Enforce TLS/SSL for LDAP connections. Validate certificate chains and avoid plaintext LDAP.
  • Medium · WebSocket Usage Without Origin Validation — api dependencies (github.com/gorilla/websocket v1.5.3). The application uses gorilla/websocket for real-time features. Without proper origin checking, this could be vulnerable to Cross-Site WebSocket Hijacking (CSWSH) attacks. Fix: Implement WebSocket origin validation. Check the Origin header against a whitelist of allowed origins. Use gorilla/websocket's CheckOrigin function properly configured.
  • Medium · Cookie Security Configuration — api/auth.go and dependencies (github.com/gorilla/securecookie). The application uses gorilla/securecookie but without code review, it's unclear if HttpOnly, Secure, and SameSite flags are properly configured for all cookies. Fix: Ensure all cookies have HttpOnly=true, Secure=true (for HTTPS), and SameSite=Strict or SameSite=Lax. Review cookie creation in authentication flows.
  • Medium · Missing Content Security Policy Headers — api/router.go and HTTP response handling. The file structure suggests a frontend application served alongside the API. Without explicit CSP headers configuration, the application may be vulnerable to XSS attacks. Fix: Implement strict Content-Security-Policy headers. Use gorilla/handlers for security headers middleware. Define CSP rules to disable unsafe-inline scripts.
  • Medium · Potential Shell Command Injection via PowerShell/Ansible — undefined. The application executes PowerShell, Ansible, and Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · semaphoreui/semaphore — RepoPilot