Skip to content

feat: template volume mounts, dialog improvements, compose split#1

Merged
SYM01 merged 3 commits intomainfrom
dev
Apr 2, 2026
Merged

feat: template volume mounts, dialog improvements, compose split#1
SYM01 merged 3 commits intomainfrom
dev

Conversation

@SYM01
Copy link
Copy Markdown
Contributor

@SYM01 SYM01 commented Apr 2, 2026

Summary

  • Add volume mounts to templates — namespaced per owner (<username>-<name>), shared across all sessions using the template
  • Template create/edit dialog: wider layout, scrollable content, resizable system prompt, shadcn Select for volume picker, discard changes confirmation
  • Admin volume management: view all managed volumes (agent + template), delete with confirm dialog
  • Session stop/destroy loading state in confirm dialog
  • Volume name regex validation (FE + BE) via shared server/lib/validation.ts
  • Split compose.yml (prod, pulls image) and compose.dev.yml (dev, builds locally)
  • Fix public templates query (mine param as enum)

Test plan

  • npx tsc --noEmit — zero errors
  • npm test — 81 unit tests pass
  • E2E tests — 24 pass, 6 skipped (Docker-gated)
  • Create template with volume mount → verify volume name stored without prefix
  • Create session with template → verify Docker bind uses <username>-<name>:<mountPath>
  • Admin: delete volume from Settings > Docker
  • Template dialog: edit then close → discard confirmation appears

🤖 Generated with Claude Code

SYM01 and others added 3 commits April 2, 2026 14:33
…ose files

- Widen template create/edit dialog and add scroll overflow to prevent
  exceeding viewport height
- Fix public templates not showing by replacing z.coerce.boolean() with
  explicit string enum transform (string "false" was coerced to true)
- Split compose.yml into production (pulls ghcr image) and compose.dev.yml
  (builds from local Dockerfile)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Widen dialog to sm:max-w-4xl with scrollable content area
- Add resize-y to system prompt textarea
- Prompt "Discard Changes" confirmation when closing with unsaved edits
- Track initial form state via ref, compare on close

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Volume Mounts:
- Add volumeMounts to templates schema + migration
- Template volumes namespaced as <owner-username>-<name> at session bind time
- Volume name regex validation (shared via server/lib/validation.ts)
- Template dialog: Select existing volumes or create new, info tooltip
- Agent config: HTML pattern validation on volume name input
- Settings/Docker: show template-referenced volumes, admin delete with confirm

Session Actions:
- Add loading state to stop/destroy confirm dialog (Stopping.../Destroying...)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@SYM01 SYM01 merged commit bb28351 into main Apr 2, 2026
2 checks passed
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Docker volume mounts within templates and provides an administrative interface for managing Docker volumes. Key changes include database schema updates to store volume configurations, backend logic to mount volumes during session creation, and frontend enhancements for template management and volume administration. Feedback highlights a security concern regarding unrestricted volume deletion, a redundant database query in session creation, and the need for stricter input validation for mount paths to ensure they are absolute.

Comment thread server/api/settings.ts
Comment on lines +534 to +546
.delete("/volumes/:name", adminMiddleware, async (c) => {
const volumeName = c.req.param("name");
try {
const docker = await getDockerClient();
await docker.getVolume(volumeName).remove();
return c.json({ success: true });
} catch (err) {
return c.json(
{ error: `Failed to delete volume: ${err instanceof Error ? err.message : String(err)}` },
500,
);
}
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

This endpoint allows an administrator to delete any Docker volume by name without verifying if it is a 'managed' volume (one created by an agent or template). This could lead to accidental deletion of critical system volumes like postgres_data. You should validate that the volumeName belongs to the set of managed volumes before proceeding with the deletion.

Comment thread server/api/sessions.ts
Comment on lines +284 to +288
const [templateOwner] = await db
.select({ username: schema.user.username, id: schema.user.id })
.from(schema.user)
.where(eq(schema.user.id, template.userId))
.limit(1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This database query is redundant. The template object is already available in the scope. You should join the user table when fetching the template earlier in the handler to avoid an extra round-trip to the database for every session creation.

Comment thread server/lib/validation.ts
export const volumeMountSchema = z.array(
z.object({
name: z.string().regex(VOLUME_NAME_RE, "Invalid volume name"),
mountPath: z.string().min(1),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The mountPath should be validated to ensure it is an absolute path (starting with /). Docker bind mounts typically require absolute paths for the container-side destination. Using a relative path can lead to unexpected behavior or container startup failures.

References
  1. Ensure input validation is robust and follows expected formats for external system calls (Docker). (link)

Comment on lines +360 to +363
items={[
{ label: "New volume...", value: "__new__" },
...existingVolumes.map((v) => ({ label: v.name, value: v.name })),
]}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The items prop is not a standard property for the shadcn/ui Select component (which is a wrapper around Radix UI). The options are already being rendered manually inside SelectContent using SelectItem. This prop is redundant and should be removed to avoid confusion.

References
  1. Adhere to component library APIs to maintain code clarity and avoid redundant props. (link)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant