Sem 115 feature perproject configurable proxy definitions ssh socks - #4123
Conversation
- Introduced Proxy struct and related Backup types to handle SSH jump hosts. - Updated InventoryService to fetch and deserialize proxy SSH keys. - Enhanced LocalExecutor to manage proxy key installations and SSH arguments. - Added new API endpoints for managing proxies within projects, including CRUD operations. - Implemented workflow management features, allowing creation, retrieval, and execution of workflows. - Updated Swagger API documentation to reflect new proxy and workflow definitions.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe change adds project SSH proxy support across storage, APIs, backups, task execution, and the web UI. It also expands the Swagger specification for options, workflows, runners, templates, views, and related endpoints. ChangesSSH proxy support
API specification updates
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant ProxiesView
participant ProxyAPI
participant SqlDb
User->>ProxiesView: Create or edit proxy
ProxiesView->>ProxyAPI: Submit proxy request
ProxyAPI->>SqlDb: CreateProxy or UpdateProxy
SqlDb-->>ProxyAPI: Proxy result
ProxyAPI-->>ProxiesView: JSON response
ProxiesView-->>User: Refresh proxy list
sequenceDiagram
participant Inventory
participant LocalExecutor
participant Ansible
Inventory->>LocalExecutor: Provide proxy configuration
LocalExecutor->>Ansible: Pass ProxyJump SSH arguments
Ansible-->>LocalExecutor: Run inventory tasks
LocalExecutor->>LocalExecutor: Clean up proxy key
Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
db/sql/inventory.go (1)
45-55: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winVerify proxy ownership before persisting
ProxyID.Both methods persist
inventory.ProxyIDwithout verifying that the proxy belongs toinventory.ProjectID. The foreign key accepts a proxy from another project because it checks only the proxy ID. This creates an invalid cross-project association.Before each write, resolve a non-nil
ProxyIDwithGetProxy(inventory.ProjectID, *inventory.ProxyID)and return its error. Add create and update tests that reject a proxy from another project.Also applies to: 68-81
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@db/sql/inventory.go` around lines 45 - 55, Before persisting ProxyID in both inventory create and update methods, validate non-nil values by calling GetProxy with inventory.ProjectID and the dereferenced proxy ID, returning any error before the write. Preserve nil ProxyID handling, and add create/update tests confirming proxies from another project are rejected.
🧹 Nitpick comments (2)
web/src/views/project/Proxies.vue (2)
67-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winGate the edit and delete actions with the same permission as the create button.
Line 43 hides the create button behind
can(USER_PERMISSIONS.manageProjectResources). The edit and delete buttons carry no guard. A user without the permission sees actions that the API rejects.♻️ Proposed fix for consistent gating
<template v-slot:item.actions="{ item }"> - <v-btn-toggle dense :value-comparator="() => false"> + <v-btn-toggle + dense + :value-comparator="() => false" + v-if="can(USER_PERMISSIONS.manageProjectResources)" + >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/views/project/Proxies.vue` around lines 67 - 76, Gate the edit and delete action controls in the item.actions slot with the same can(USER_PERMISSIONS.manageProjectResources) permission check used by the create button. Ensure users lacking this permission cannot see either action while preserving the existing askDeleteItem and editItem handlers for authorized users.
3-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winLocalize the dialog title and the object title.
Line 6 builds the title with the literal English word
Proxy. Line 23 passes the literalproxyasobject-title. Both strings appear in the UI and bypass vue-i18n. ThenewProxyandproxieskeys already exist inweb/src/lang/en.js.♻️ Proposed fix to use translation keys
:save-button-text="itemId === 'new' ? $t('create') : $t('save')" - :title="`${itemId === 'new' ? $t('nnew') : $t('edit')} Proxy`" + :title="itemId === 'new' ? $t('newProxy') : $t('editProxy')"Add the missing key to
web/src/lang/en.js:editProxy: 'Edit Proxy',🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/views/project/Proxies.vue` around lines 3 - 27, Update the EditDialog title and ObjectRefsDialog object-title in Proxies.vue to use the existing vue-i18n proxy translation keys instead of the literal “Proxy” and “proxy” strings; add the editProxy key to en.js if needed and preserve the existing create/edit title behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@api-docs.yml`:
- Around line 2978-2991: Add the missing ObjectReferrers definition to
api-docs.yml, matching the schema expected by the
/project/{project_id}/proxies/{proxy_id}/refs response, and duplicate the same
definition in web/public/swagger/api-docs.yml so both
`#/definitions/ObjectReferrers` references resolve.
In `@db/sql/migrations/v2.20.2.sql`:
- Around line 1-13: Update the project__proxy table definition in migration
v2.20.2 to enforce UNIQUE(project_id, name), then add a regression test covering
creation of two proxies with the same name in one project and asserting the
duplicate is rejected.
In `@services/project/backup.go`:
- Around line 369-379: Update the backup name-normalization flow in
makeUniqueNames to include b.proxies, ensuring each project’s proxy names are
unique before BackupProxy serialization and restore lookup via findEntityByName.
Preserve the existing naming behavior for other entities and ensure the
normalized names are used by BackupProxy.Name.
In `@services/tasks/local_executor_inventory.go`:
- Around line 57-65: Update getInventorySSHCommonArgs to generate a unique SSH
config alias for the proxy jump host containing its HostName, User, Port, and
proxy SSHAgent SocketFile, then use that alias in ProxyJump instead of applying
IdentityAgent to destination options. In
services/tasks/local_executor_inventory.go:57-65 implement the jump-host
configuration; in services/tasks/local_executor_test.go:74-85 add coverage with
a proxy SSH key asserting IdentityAgent is configured on the jump-host alias
rather than only on destination options.
In `@web/src/components/ProxyForm.vue`:
- Around line 47-56: Update the ProxyForm save flow to normalize an empty port
value to null before submitting the request, and ensure zero is rejected by the
port validation rule. Locate the relevant save handler and port field rules in
ProxyForm.vue; preserve valid ports from 1 through 65535 and keep the nullable
API contract intact.
In `@web/src/views/project/Proxies.vue`:
- Around line 57-61: Update the item.host slot template to render a clear
separator between the host text and the conditional port value, while preserving
the existing user@host formatting and omitting the separator when item.port is
absent.
---
Outside diff comments:
In `@db/sql/inventory.go`:
- Around line 45-55: Before persisting ProxyID in both inventory create and
update methods, validate non-nil values by calling GetProxy with
inventory.ProjectID and the dereferenced proxy ID, returning any error before
the write. Preserve nil ProxyID handling, and add create/update tests confirming
proxies from another project are rejected.
---
Nitpick comments:
In `@web/src/views/project/Proxies.vue`:
- Around line 67-76: Gate the edit and delete action controls in the
item.actions slot with the same can(USER_PERMISSIONS.manageProjectResources)
permission check used by the create button. Ensure users lacking this permission
cannot see either action while preserving the existing askDeleteItem and
editItem handlers for authorized users.
- Around line 3-27: Update the EditDialog title and ObjectRefsDialog
object-title in Proxies.vue to use the existing vue-i18n proxy translation keys
instead of the literal “Proxy” and “proxy” strings; add the editProxy key to
en.js if needed and preserve the existing create/edit title behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b4c6dab7-6e57-42d4-852e-260d67f51407
📒 Files selected for processing (29)
api-docs.ymlapi/projects/proxies.goapi/router.godb/BackupEntity.godb/Event.godb/Inventory.godb/Migration.godb/Proxy.godb/Proxy_test.godb/Store.godb/sql/inventory.godb/sql/migrations/v2.20.2.err.sqldb/sql/migrations/v2.20.2.sqldb/sql/proxy.goservices/project/backup.goservices/project/backup_test.goservices/project/restore.goservices/project/types.goservices/server/inventory_svc.goservices/tasks/local_executor.goservices/tasks/local_executor_inventory.goservices/tasks/local_executor_test.goweb/public/swagger/api-docs.ymlweb/src/App.vueweb/src/components/InventoryForm.vueweb/src/components/ProxyForm.vueweb/src/lang/en.jsweb/src/router/index.jsweb/src/views/project/Proxies.vue
…perproject-configurable-proxy-definitions-ssh-socks
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
db/Proxy.go (1)
72-86: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winHandle already-bracketed IPv6 hosts before
net.JoinHostPort.
Destinationpassesp.Hostdirectly tonet.JoinHostPort. A host such as[2001:db8::1]contains a colon, so using a port produces[[2001:db8::1]]:2222. Normalize one outer bracket pair before joining, or reject bracketed input, and add a regression test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@db/Proxy.go` around lines 72 - 86, Update Proxy.Destination to normalize a single outer bracket pair from p.Host before calling net.JoinHostPort, so already-bracketed IPv6 hosts produce exactly one bracket pair with a port. Preserve existing user-prefix and unported-host behavior, and add a regression test covering a bracketed IPv6 host with a port.Source: MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@db/Proxy.go`:
- Around line 59-61: Update proxy validation around the SSHKeyID check to
resolve the referenced access key using proxy.ProjectID, require it to be an
AccessKeySSH key, and reject missing, cross-project, or mismatched key types
before persistence. Apply this validation to both CreateProxy and UpdateProxy,
and add tests covering valid keys and rejected invalid or cross-project keys.
---
Outside diff comments:
In `@db/Proxy.go`:
- Around line 72-86: Update Proxy.Destination to normalize a single outer
bracket pair from p.Host before calling net.JoinHostPort, so already-bracketed
IPv6 hosts produce exactly one bracket pair with a port. Preserve existing
user-prefix and unported-host behavior, and add a regression test covering a
bracketed IPv6 host with a port.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: acf993ef-00d9-4156-9864-d9439412725e
📒 Files selected for processing (2)
db/Proxy.goservices/project/backup_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
- services/project/backup_test.go
…perproject-configurable-proxy-definitions-ssh-socks
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…ns-ssh-socks' of github.com:befika/semaphore into sem-115-feature-perproject-configurable-proxy-definitions-ssh-socks
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/components/ProxyForm.vue`:
- Line 51: Update the port validation in ProxyForm.vue so the ProxyForm port
field rejects fractional values like 22.5 before submission; adjust the rule
attached to the port input to require an integer (or convert the value to an
integer before saving) while still allowing empty/null values and the existing
1–65535 range, and update the port input itself to use type="number" with
step="1" so it matches the nullable integer contract.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: de66d557-c720-4243-997c-853feb668e54
📒 Files selected for processing (12)
.dredd/hooks/capabilities.go.dredd/hooks/main.goapi-docs.ymlapi/projects/proxies.godb/Store.godb/sql/migrations/v2.20.2.sqldb/sql/proxy_test.goservices/tasks/local_executor.goservices/tasks/local_executor_test.goweb/public/swagger/api-docs.ymlweb/src/components/ProxyForm.vueweb/src/lang/en.js
🚧 Files skipped from review as they are similar to previous changes (7)
- web/src/lang/en.js
- db/sql/migrations/v2.20.2.sql
- services/tasks/local_executor.go
- services/tasks/local_executor_test.go
- api-docs.yml
- api/projects/proxies.go
- web/public/swagger/api-docs.yml
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds project-scoped SSH proxy (jump host) support across the Semaphore stack (DB/API/UI/executor) so inventories can route SSH connections through a selected proxy, and the configuration survives backup/restore.
Changes:
- Introduces a new
Proxymodel + persistence (SQL migration, store methods) and exposes CRUD + refs endpoints under/api/project/{project_id}/proxies. - Adds UI for managing proxies and selecting a proxy on inventories.
- Updates the Ansible local executor to pass proxy-related SSH options, and extends backup/restore + API docs/test hooks accordingly.
Reviewed changes
Copilot reviewed 32 out of 32 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| web/src/views/project/Proxies.vue | New project Proxies list + edit/delete dialogs |
| web/src/router/index.js | Adds /project/:projectId/proxies route |
| web/src/lang/en.js | Adds i18n strings for proxies + inventory proxy selector |
| web/src/components/ProxyForm.vue | New proxy create/edit form |
| web/src/components/InventoryForm.vue | Adds proxy selection field and loads proxies |
| web/src/App.vue | Adds “Proxies” nav entry |
| web/public/swagger/api-docs.yml | Documents proxy endpoints/models (and other API additions) |
| services/tasks/local_executor.go | Passes --ssh-common-args when inventory has a proxy |
| services/tasks/local_executor_test.go | Adds unit tests for proxy SSH args and playbook args |
| services/tasks/local_executor_inventory.go | Installs proxy key agent + builds SSH common args |
| services/server/inventory_svc.go | Loads inventory proxy (and decrypts proxy SSH key) |
| services/project/types.go | Extends backup schema with proxies + inventory-to-proxy reference |
| services/project/restore.go | Restores proxies before inventories; validates proxy references |
| services/project/backup.go | Includes proxies in backups; serializes inventory proxy by name |
| services/project/backup_test.go | Adds backup/restore round-trip test for proxies |
| db/Store.go | Adds proxy CRUD/ref methods to store interface + proxy object metadata |
| db/sql/proxy.go | SQL store implementation for proxy CRUD + refs |
| db/sql/proxy_test.go | Tests proxy key validation (same project + SSH-only) |
| db/sql/migrations/v2.20.2.sql | Adds project__proxy and inventory.proxy_id |
| db/sql/migrations/v2.20.2.err.sql | Down migration for proxy table/column |
| db/sql/inventory.go | Persists proxy_id in inventory create/update |
| db/Proxy.go | Adds Proxy model, validation, and ProxyJump destination rendering |
| db/Proxy_test.go | Tests proxy validation and destination formatting |
| db/Migration.go | Registers migration 2.20.2 |
| db/Inventory.go | Adds ProxyID/Proxy fields to inventory |
| db/Event.go | Adds EventProxy object type |
| db/BackupEntity.go | Adds backup entity helpers for Proxy |
| api/router.go | Wires proxy routes + middleware |
| api/projects/proxies.go | Implements proxy CRUD + refs handlers |
| api-docs.yml | Documents proxy endpoints/models (and other API additions) |
| .dredd/hooks/main.go | Adds Dredd hooks for proxy endpoints |
| .dredd/hooks/capabilities.go | Adds proxy capability setup and request body/path substitution |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…ns-ssh-socks' of github.com:befika/semaphore into sem-115-feature-perproject-configurable-proxy-definitions-ssh-socks
…roxy-definitions-ssh-socks
There was a problem hiding this comment.
🟡 Changes recommended
Proxy routing currently has command-injection risks, remote-runner omissions, and several configurations that silently bypass or fail to use the selected proxy.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 56/56 changed files
- Comments generated: 17
- Review effort level: Balanced
…roxy-definitions-ssh-socks
…H proxies in inventory
Summary by CodeRabbit
New Features
Backup and Restore
Documentation