mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dc94c90b2 | ||
|
|
eb8b465c92 | ||
|
|
3559a6fd87 | ||
|
|
b70fa4cd52 | ||
|
|
43b833c4ae | ||
|
|
38560b8178 | ||
|
|
4a33024b7f | ||
|
|
38f836b94f | ||
|
|
4b53139c20 | ||
|
|
e0a86b9e18 | ||
|
|
b58b6e729c | ||
|
|
6eff103cae | ||
|
|
137f8ef472 | ||
|
|
0ca1392670 | ||
|
|
c2ed2729be | ||
|
|
a92ed01129 | ||
|
|
1cab763bee | ||
|
|
30bcdd440e | ||
|
|
bc4c2dc7e6 | ||
|
|
962f0064fe | ||
|
|
eb3008d097 | ||
|
|
64ac578d61 | ||
|
|
50de22618a | ||
|
|
493514d7fa | ||
|
|
27495aa4ed | ||
|
|
babe105b2e | ||
|
|
ec2a1f4215 | ||
|
|
6ed822c8b2 | ||
|
|
634e625eef | ||
|
|
32945adcd9 | ||
|
|
5e88f8496e | ||
|
|
abeba66432 | ||
|
|
073e9a969b | ||
|
|
2e62dee798 | ||
|
|
608111c37b | ||
|
|
547701378f | ||
|
|
cfaa04e42c | ||
|
|
49a4d20740 | ||
|
|
00a827df09 |
No files matched your search
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": ["@commitlint/config-conventional"],
|
||||
"rules": {
|
||||
"subject-case": [0]
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
dist
|
||||
build
|
||||
coverage
|
||||
release
|
||||
|
||||
# Local data, secrets and editor state
|
||||
db
|
||||
old_db
|
||||
ssl
|
||||
uploads
|
||||
plugins
|
||||
.env
|
||||
.env.*
|
||||
.mcp.json
|
||||
.claude
|
||||
CLAUDE.md
|
||||
termix-plugin-signing.key
|
||||
*.tmxplug.sig
|
||||
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
.git
|
||||
.gitignore
|
||||
.husky
|
||||
|
||||
README.md
|
||||
CONTRIBUTING.md
|
||||
CHANGELOG.md
|
||||
LICENSE
|
||||
|
||||
electron/
|
||||
electron-builder.json
|
||||
Casks
|
||||
packaging
|
||||
|
||||
*.log
|
||||
*.tmp
|
||||
*.temp
|
||||
logs
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
.nyc_output
|
||||
.npm
|
||||
.eslintcache
|
||||
.cache
|
||||
.parcel-cache
|
||||
*.tgz
|
||||
.node_repl_history
|
||||
@@ -1,17 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.webp binary
|
||||
*.ico binary
|
||||
*.icns binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
@@ -0,0 +1 @@
|
||||
github: [LukeGus]
|
||||
@@ -1,75 +0,0 @@
|
||||
name: Beta feedback
|
||||
description: A bug, rough edge or idea from a Termix beta
|
||||
labels: [beta]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for testing a beta. Short reports are fine. If you opened this from Termix, the version and setup are already filled in.
|
||||
- type: input
|
||||
id: termix-version
|
||||
attributes:
|
||||
label: Beta version
|
||||
description: Shown in Settings under Updates, or your image tag.
|
||||
placeholder: "e.g. 26.11.0-beta.2"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: The bug, what felt off, or your idea. Screenshots help a lot.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: regression
|
||||
attributes:
|
||||
label: Does this happen on the latest stable release?
|
||||
options:
|
||||
- "Not tested on stable"
|
||||
- "Yes, it happens on stable too"
|
||||
- "No, only on this beta"
|
||||
- "Not a bug, just feedback"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: As few steps as you can.
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: beta-plugins
|
||||
attributes:
|
||||
label: Plugins on a beta
|
||||
description: Filled in by Termix. One plugin and version per line.
|
||||
render: text
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: Browser or desktop app, OS, and how the server is installed.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs
|
||||
description: Errors from the browser console, `docker logs termix`, or the error Termix shows. This is shown as code, so no backticks needed.
|
||||
render: text
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Before you submit
|
||||
options:
|
||||
- label: I searched open issues and this is not a duplicate
|
||||
required: true
|
||||
@@ -1,107 +0,0 @@
|
||||
name: Bug report
|
||||
description: Something in Termix itself is broken
|
||||
labels: [bug]
|
||||
type: Bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for the report. A maintainer reads every issue, even when there is no reply right away. We usually reply once there is a fix or a workaround.
|
||||
|
||||
If you came from **Report an issue** in Termix, your versions and environment are already filled in below.
|
||||
|
||||
Is it about a plugin (terminal, file manager, Docker, remote desktop and so on)? Report it on that plugin's repo instead. **Report an issue** on the plugin's page in Termix takes you there with your versions filled in.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Describe the bug. Screenshots help a lot.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: As few steps as you can.
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: What did you expect?
|
||||
description: What should have happened instead?
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: termix-version
|
||||
attributes:
|
||||
label: Termix version
|
||||
description: Shown in Settings under About, or in your User Profile.
|
||||
placeholder: "e.g. 26.10.0"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: Platform
|
||||
description: Where do you see the problem?
|
||||
options:
|
||||
- "Web browser"
|
||||
- "Desktop app (Windows)"
|
||||
- "Desktop app (macOS)"
|
||||
- "Desktop app (Linux)"
|
||||
- "Mobile app (iOS)"
|
||||
- "Mobile app (Android)"
|
||||
- "Other"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: install-method
|
||||
attributes:
|
||||
label: Server install
|
||||
description: How is the Termix server installed?
|
||||
options:
|
||||
- "Docker"
|
||||
- "Manual build"
|
||||
- "Proxmox community script"
|
||||
- "Desktop app (built-in server)"
|
||||
- "Not sure"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: Browser and OS, plus anything special about your setup (reverse proxy, database, SSO).
|
||||
placeholder: |
|
||||
Web, Chrome on Windows. Behind nginx, Postgres.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs
|
||||
description: Errors from the browser console, `docker logs termix`, or the error Termix shows. This is shown as code, so no backticks needed.
|
||||
render: text
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: Links, config, or anything that might help.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Before you submit
|
||||
options:
|
||||
- label: I searched open and closed issues and this is not a duplicate
|
||||
required: true
|
||||
- label: I am on the latest version, or I said which version I am on
|
||||
required: true
|
||||
@@ -1,11 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Problem with a plugin?
|
||||
url: https://github.com/Termix-SSH/Termix#plugins
|
||||
about: Each plugin has its own repo. Find it in this list, or use Report an issue on the plugin's page in Termix.
|
||||
- name: Questions and chat
|
||||
url: https://discord.gg/jVQGdvHDrf
|
||||
about: Ask the community on Discord. Bugs and ideas belong in issues.
|
||||
- name: Business or priority support
|
||||
url: https://termix.site/contact
|
||||
about: For teams that need a faster response. Contact us to discuss terms.
|
||||
@@ -1,41 +0,0 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for Termix itself
|
||||
labels: [feature]
|
||||
type: Feature
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Is it about a plugin (terminal, file manager, Docker, remote desktop and so on)? Report it on that plugin's repo instead. **Report an issue** on the plugin's page in Termix takes you there with your versions filled in.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for the idea. Explain the problem first, then how you would solve it.
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: What problem would this solve?
|
||||
description: What are you trying to do, and what gets in the way today?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: What would you like?
|
||||
description: Describe how it should work.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives
|
||||
description: Anything you tried or considered instead.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: Screenshots, mockups or links.
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,116 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- development
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '.gitignore'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: "Custom tag name for the Docker image"
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [self-hosted, linux]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: arm64
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
driver-opts: |
|
||||
image=moby/buildkit:master
|
||||
network=host
|
||||
|
||||
- name: Cache npm dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
node_modules
|
||||
*/*/node_modules
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.ref_name }}-${{ hashFiles('docker/Dockerfile') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-${{ github.ref_name }}-
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Determine Docker image tag
|
||||
run: |
|
||||
echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
if [ "${{ github.event.inputs.tag_name }}" != "" ]; then
|
||||
IMAGE_TAG="${{ github.event.inputs.tag_name }}"
|
||||
elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
IMAGE_TAG="latest"
|
||||
elif [ "${{ github.ref }}" == "refs/heads/development" ]; then
|
||||
IMAGE_TAG="development-latest"
|
||||
else
|
||||
IMAGE_TAG="${{ github.ref_name }}-development-latest"
|
||||
fi
|
||||
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and Push Multi-Arch Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ghcr.io/${{ env.REPO_OWNER }}/termix:${{ env.IMAGE_TAG }}
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
|
||||
build-args: |
|
||||
BUILDKIT_INLINE_CACHE=1
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
outputs: type=registry,compression=zstd,compression-level=19
|
||||
|
||||
- name: Move cache
|
||||
run: |
|
||||
rm -rf /tmp/.buildx-cache
|
||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||
|
||||
- name: Delete all untagged image versions
|
||||
if: success()
|
||||
uses: quartx-analytics/ghcr-cleaner@v1
|
||||
with:
|
||||
owner-type: user
|
||||
token: ${{ secrets.GHCR_TOKEN }}
|
||||
repository-owner: ${{ github.repository_owner }}
|
||||
delete-untagged: true
|
||||
|
||||
- name: Cleanup Docker Images Locally
|
||||
if: always()
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker system prune -af --volumes
|
||||
@@ -1,157 +0,0 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version to build (e.g., 26.10.0)"
|
||||
required: true
|
||||
build_type:
|
||||
description: "Build type"
|
||||
required: true
|
||||
default: "Development"
|
||||
type: choice
|
||||
options:
|
||||
- Development
|
||||
- Beta
|
||||
- Production
|
||||
source_ref:
|
||||
description: "Git ref/SHA to build (defaults to the workflow ref)"
|
||||
required: false
|
||||
default: ""
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version to build (e.g., 26.10.0)"
|
||||
required: true
|
||||
type: string
|
||||
build_type:
|
||||
description: "Build type (Development, Beta or Production)"
|
||||
required: true
|
||||
type: string
|
||||
dry_run:
|
||||
description: "Build the image but do not push to any registry"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
source_ref:
|
||||
description: "Git ref/SHA to build"
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.source_ref || github.ref }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Resolve source revision
|
||||
run: |
|
||||
echo "SOURCE_SHA=$(git rev-parse HEAD)" >> "$GITHUB_ENV"
|
||||
echo "BUILD_CREATED=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
|
||||
|
||||
# The image reads its version from package.json, so a beta has to say so.
|
||||
- name: Stamp beta version
|
||||
if: ${{ inputs.build_type == 'Beta' }}
|
||||
run: node scripts/sync-version.cjs --version "${{ inputs.version }}"
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: useblacksmith/setup-docker-builder@v2
|
||||
with:
|
||||
cache-key: termix-ssh/termix
|
||||
|
||||
- name: Determine tags
|
||||
id: tags
|
||||
run: |
|
||||
VERSION=${{ inputs.version }}
|
||||
BUILD_TYPE=${{ inputs.build_type }}
|
||||
|
||||
TAGS=()
|
||||
ALL_TAGS=()
|
||||
|
||||
if [ "$BUILD_TYPE" = "Production" ]; then
|
||||
TAGS+=("$VERSION" "latest")
|
||||
elif [ "$BUILD_TYPE" = "Beta" ]; then
|
||||
TAGS+=("beta" "$VERSION")
|
||||
else
|
||||
TAGS+=("dev-$VERSION")
|
||||
fi
|
||||
|
||||
for tag in "${TAGS[@]}"; do
|
||||
ALL_TAGS+=("ghcr.io/lukegus/termix:$tag")
|
||||
ALL_TAGS+=("ghcr.io/termix-ssh/termix:$tag")
|
||||
if [ "$BUILD_TYPE" != "Development" ]; then
|
||||
ALL_TAGS+=("docker.io/bugattiguy527/termix:$tag")
|
||||
fi
|
||||
done
|
||||
|
||||
echo "ALL_TAGS=$(IFS=,; echo "${ALL_TAGS[*]}")" >> $GITHUB_ENV
|
||||
echo "TAGS=${TAGS[*]}" >> $GITHUB_ENV
|
||||
|
||||
- name: Login to GHCR
|
||||
if: ${{ !inputs.dry_run }}
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: lukegus
|
||||
password: ${{ secrets.TERMIX_PAT }}
|
||||
|
||||
- name: Login to Docker Hub (prod and beta only)
|
||||
if: ${{ (inputs.build_type == 'Production' || inputs.build_type == 'Beta') && !inputs.dry_run }}
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: bugattiguy527
|
||||
password: ${{ secrets.DOCKERHUB_BUGATTIGUY527_TOKEN }}
|
||||
|
||||
- name: Build and push multi-arch image
|
||||
uses: useblacksmith/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: ${{ !inputs.dry_run }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ env.ALL_TAGS }}
|
||||
build-args: |
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
labels: |
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.revision=${{ env.SOURCE_SHA }}
|
||||
org.opencontainers.image.created=${{ env.BUILD_CREATED }}
|
||||
outputs: ${{ inputs.dry_run && 'type=cacheonly' || 'type=registry,compression=zstd' }}
|
||||
|
||||
- name: Login to Docker Hub as termixssh
|
||||
id: termix_hub
|
||||
if: ${{ (inputs.build_type == 'Production' || inputs.build_type == 'Beta') && !inputs.dry_run }}
|
||||
env:
|
||||
TOKEN: ${{ secrets.DOCKERHUB_TERMIXSSH_TOKEN }}
|
||||
run: |
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "DOCKERHUB_TERMIXSSH_TOKEN is not set, skipping docker.io/termixssh"
|
||||
exit 0
|
||||
fi
|
||||
echo "$TOKEN" | docker login docker.io --username termixssh --password-stdin
|
||||
echo "ready=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Copy image to docker.io/termixssh
|
||||
if: ${{ steps.termix_hub.outputs.ready == 'true' }}
|
||||
run: |
|
||||
for tag in $TAGS; do
|
||||
docker buildx imagetools create --tag "docker.io/termixssh/termix:$tag" "ghcr.io/termix-ssh/termix:$tag"
|
||||
done
|
||||
|
||||
- name: Cleanup Docker
|
||||
if: always()
|
||||
run: |
|
||||
docker image prune -af
|
||||
docker system prune -af --volumes
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,111 +0,0 @@
|
||||
name: PR Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, dev-*]
|
||||
|
||||
jobs:
|
||||
lint-and-build:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build plugin SDK
|
||||
run: npm run build:sdk
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Run Prettier check
|
||||
run: npx prettier --check .
|
||||
|
||||
- name: Type check
|
||||
run: npm run type-check
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test
|
||||
|
||||
database-dialects:
|
||||
name: Postgres and MySQL
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
env:
|
||||
POSTGRES_USER: termix
|
||||
POSTGRES_PASSWORD: termix
|
||||
POSTGRES_DB: termix_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
mysql:
|
||||
image: mysql:8
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: termix
|
||||
MYSQL_DATABASE: termix_test
|
||||
MYSQL_USER: termix
|
||||
MYSQL_PASSWORD: termix
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: >-
|
||||
--health-cmd "mysqladmin ping -h 127.0.0.1 -ptermix"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 10
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build plugin SDK
|
||||
run: npm run build:sdk
|
||||
|
||||
- name: Verify Postgres
|
||||
run: npm run verify:dialect -- postgres://termix:termix@127.0.0.1:5432/termix_test
|
||||
|
||||
- name: Verify MySQL
|
||||
run: npm run verify:dialect -- mysql://termix:termix@127.0.0.1:3306/termix_test
|
||||
|
||||
- name: Repository tests on Postgres
|
||||
env:
|
||||
TEST_DIALECT: postgres
|
||||
TEST_DATABASE_URL: postgres://termix:termix@127.0.0.1:5432/termix_test
|
||||
run: npx vitest run src/backend/tests/database/repositories --no-file-parallelism
|
||||
|
||||
- name: Repository tests on MySQL
|
||||
env:
|
||||
TEST_DIALECT: mysql
|
||||
TEST_DATABASE_URL: mysql://termix:termix@127.0.0.1:3306/termix_test
|
||||
run: npx vitest run src/backend/tests/database/repositories --no-file-parallelism
|
||||
@@ -1,84 +0,0 @@
|
||||
name: Publish SDK
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
mode:
|
||||
description: "Publish mode"
|
||||
required: true
|
||||
default: Publish
|
||||
type: choice
|
||||
options:
|
||||
- Publish
|
||||
- Dry run
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish @termix-ssh/plugin-sdk
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: npm
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: Update npm
|
||||
run: npm install -g npm@^11.19.0
|
||||
|
||||
- run: npm ci
|
||||
|
||||
- name: Check the version is new
|
||||
run: |
|
||||
VERSION=$(node -p "require('./packages/plugin-sdk/package.json').version")
|
||||
if npm view "@termix-ssh/plugin-sdk@$VERSION" version >/dev/null 2>&1; then
|
||||
echo "@termix-ssh/plugin-sdk@$VERSION is already on npm. Bump packages/plugin-sdk/package.json first."
|
||||
if [ "${{ inputs.mode }}" = "Publish" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "Publishing @termix-ssh/plugin-sdk@$VERSION"
|
||||
|
||||
- run: npm run build:sdk
|
||||
|
||||
- run: npm run lint
|
||||
|
||||
- run: npm run type-check
|
||||
|
||||
- run: npm run test
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
if [ "${{ inputs.mode }}" = "Dry run" ]; then
|
||||
npm publish --workspace @termix-ssh/plugin-sdk --provenance --access public --dry-run
|
||||
else
|
||||
npm publish --workspace @termix-ssh/plugin-sdk --provenance --access public
|
||||
fi
|
||||
|
||||
- name: Tag and release
|
||||
if: ${{ inputs.mode == 'Publish' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
VERSION=$(node -p "require('./packages/plugin-sdk/package.json').version")
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const { changelogSection } = require('./packages/plugin-sdk/dist/changelog.js');
|
||||
const notes = changelogSection(fs.readFileSync('packages/plugin-sdk/CHANGELOG.md', 'utf8'), process.argv[1]);
|
||||
fs.writeFileSync('sdk-notes.md', notes);
|
||||
" "$VERSION"
|
||||
gh release create "sdk-v$VERSION" \
|
||||
--target "${{ github.sha }}" \
|
||||
--title "Plugin SDK v$VERSION" \
|
||||
--notes-file sdk-notes.md \
|
||||
--latest=false
|
||||
@@ -1,665 +0,0 @@
|
||||
name: Release
|
||||
|
||||
# Stable: run by hand from a dev-X.Y.Z branch. Beta: run by hand from a dev
|
||||
# branch, or let the Tuesday and Friday schedule snapshot the newest dev
|
||||
# branch when it moved since the last beta.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 15 * * 2,5"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
channel:
|
||||
description: "Stable release or beta"
|
||||
required: true
|
||||
default: Stable
|
||||
type: choice
|
||||
options:
|
||||
- Stable
|
||||
- Beta
|
||||
mode:
|
||||
description: "Release mode (Overwrite release is stable only)"
|
||||
required: true
|
||||
default: Everything
|
||||
type: choice
|
||||
options:
|
||||
- Everything
|
||||
- Overwrite release
|
||||
- Dry run
|
||||
- Skip submit
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: release
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
prep:
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
outputs:
|
||||
channel: ${{ steps.mode.outputs.channel }}
|
||||
mode: ${{ steps.mode.outputs.mode }}
|
||||
skip: ${{ steps.beta.outputs.skip || 'false' }}
|
||||
version: ${{ steps.info.outputs.version || steps.beta.outputs.version }}
|
||||
release_tag: ${{ steps.info.outputs.release_tag || steps.beta.outputs.release_tag }}
|
||||
mobile_version: ${{ steps.info.outputs.mobile_version }}
|
||||
mobile_tag: ${{ steps.info.outputs.mobile_tag }}
|
||||
dev_branch: ${{ steps.info.outputs.dev_branch || steps.beta.outputs.dev_branch }}
|
||||
sha: ${{ steps.beta.outputs.sha }}
|
||||
prev_ref: ${{ steps.beta.outputs.prev_ref }}
|
||||
steps:
|
||||
- name: Resolve channel and mode
|
||||
id: mode
|
||||
run: |
|
||||
CHANNEL="${{ inputs.channel || 'Beta' }}"
|
||||
MODE="${{ inputs.mode || 'Everything' }}"
|
||||
echo "channel=$CHANNEL" >> "$GITHUB_OUTPUT"
|
||||
echo "mode=$MODE" >> "$GITHUB_OUTPUT"
|
||||
if [ "$CHANNEL" = "Beta" ] && [ "$MODE" = "Overwrite release" ]; then
|
||||
echo "Overwrite release is for stable releases only."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Guard branch (release modes)
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && steps.mode.outputs.mode != 'Overwrite release' && !startsWith(github.ref, 'refs/heads/dev-') }}
|
||||
run: |
|
||||
echo "This mode must be run from a dev branch (got ${{ github.ref }})."
|
||||
exit 1
|
||||
|
||||
- name: Guard branch (overwrite mode)
|
||||
if: ${{ steps.mode.outputs.mode == 'Overwrite release' && github.ref != 'refs/heads/main' }}
|
||||
run: |
|
||||
echo "Overwrite release must be run from main (got ${{ github.ref }})."
|
||||
exit 1
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Resolve versions
|
||||
id: info
|
||||
if: ${{ steps.mode.outputs.channel == 'Stable' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if [ "${{ steps.mode.outputs.mode }}" = "Overwrite release" ]; then
|
||||
DEV_BRANCH=""
|
||||
VERSION=$(node -p "require('./package.json').version")
|
||||
else
|
||||
DEV_BRANCH="${GITHUB_REF#refs/heads/}"
|
||||
VERSION=$(node scripts/parse-dev-branch.cjs "$DEV_BRANCH")
|
||||
fi
|
||||
echo "dev_branch=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "release_tag=v$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
MOBILE_RAW=$(gh release view -R Termix-SSH/Mobile --json tagName -q .tagName)
|
||||
MOBILE_VERSION=$(echo "$MOBILE_RAW" | sed -E 's/^release-//; s/-tag$//; s/^v//')
|
||||
if [ -z "$MOBILE_VERSION" ]; then
|
||||
echo "Failed to resolve the latest Termix-SSH/Mobile release version."
|
||||
exit 1
|
||||
fi
|
||||
echo "mobile_version=$MOBILE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "mobile_tag=$MOBILE_RAW" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check CHANGELOG.md has notes for this version
|
||||
if: ${{ steps.mode.outputs.channel == 'Stable' }}
|
||||
run: |
|
||||
node scripts/generate-release-body.cjs \
|
||||
--version "${{ steps.info.outputs.version }}" \
|
||||
--mobile-version "${{ steps.info.outputs.mobile_version }}" \
|
||||
--mobile-tag "${{ steps.info.outputs.mobile_tag }}" > /dev/null
|
||||
|
||||
- name: Resolve beta version
|
||||
id: beta
|
||||
if: ${{ steps.mode.outputs.channel == 'Beta' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "schedule" ]; then
|
||||
REFS=$(gh api "repos/${{ github.repository }}/branches" --paginate -q '.[].name')
|
||||
if ! DEV_BRANCH=$(printf '%s\n' "$REFS" | node scripts/latest-dev-branch.cjs 2>/dev/null); then
|
||||
echo "No dev-X.Y.Z branch is open, so no beta today."
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
DEV_BRANCH="${GITHUB_REF#refs/heads/}"
|
||||
fi
|
||||
|
||||
BASE=$(node scripts/parse-dev-branch.cjs "$DEV_BRANCH")
|
||||
SHA=$(gh api "repos/${{ github.repository }}/branches/$DEV_BRANCH" -q .commit.sha)
|
||||
TAGS=$(gh api "repos/${{ github.repository }}/git/matching-refs/tags/v$BASE-beta." -q '.[].ref' | sed 's#^refs/tags/##')
|
||||
LATEST=$(printf '%s\n' "$TAGS" | node scripts/beta-version.cjs "$BASE" --latest)
|
||||
VERSION=$(printf '%s\n' "$TAGS" | node scripts/beta-version.cjs "$BASE")
|
||||
|
||||
if [ -n "$LATEST" ]; then
|
||||
LATEST_SHA=$(gh api "repos/${{ github.repository }}/commits/$LATEST" -q .sha)
|
||||
if [ "$LATEST_SHA" = "$SHA" ] && [ "${{ github.event_name }}" = "schedule" ]; then
|
||||
echo "$DEV_BRANCH has not moved since $LATEST, so no beta today."
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
PREV="$LATEST"
|
||||
else
|
||||
PREV=$(gh release view --repo ${{ github.repository }} --json tagName -q .tagName 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
echo "Beta $VERSION from $DEV_BRANCH @ $SHA, changes since ${PREV:-nothing}"
|
||||
echo "skip=false" >> "$GITHUB_OUTPUT"
|
||||
echo "dev_branch=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "release_tag=v$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "prev_ref=$PREV" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Translates new or changed strings with the Termix LLM server and commits
|
||||
# them to the dev branch, so the beta or stable build includes them. If the
|
||||
# server is down it warns and the release goes on with what is there.
|
||||
translate:
|
||||
needs: [prep]
|
||||
if: ${{ needs.prep.outputs.skip != 'true' && needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
outputs:
|
||||
sha: ${{ steps.commit.outputs.sha }}
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.sha || needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 1
|
||||
token: ${{ secrets.TERMIX_PAT }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Translate
|
||||
uses: Termix-SSH/Termix-Registry/translate@main
|
||||
with:
|
||||
source: src/ui/locales/en.json
|
||||
out: src/ui/locales/translated
|
||||
languages: src/ui/locales/languages.json
|
||||
api-key: ${{ secrets.TERMIX_LLM_API_KEY }}
|
||||
|
||||
- name: Commit translations
|
||||
id: commit
|
||||
run: |
|
||||
git add src/ui/locales
|
||||
if git diff --cached --quiet; then
|
||||
echo "No translation changes."
|
||||
elif [ "${{ needs.prep.outputs.mode }}" = "Dry run" ]; then
|
||||
echo "DRY RUN: would commit these translation changes:"
|
||||
git --no-pager diff --cached --stat
|
||||
else
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
git commit -m "chore: update translations"
|
||||
git push origin HEAD:"${{ needs.prep.outputs.dev_branch }}"
|
||||
fi
|
||||
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
verify-beta:
|
||||
needs: [prep, translate]
|
||||
if: ${{ needs.prep.outputs.channel == 'Beta' && needs.prep.outputs.skip != 'true' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout beta commit
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.translate.outputs.sha || needs.prep.outputs.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build plugin SDK
|
||||
run: npm run build:sdk
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Type check
|
||||
run: npm run type-check
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test
|
||||
|
||||
normalize:
|
||||
needs: [prep, translate]
|
||||
if: ${{ needs.prep.outputs.channel == 'Stable' && needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.TERMIX_PAT }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "npm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# Manifest validation in lint loads the built SDK.
|
||||
- name: Build SDK
|
||||
run: npm run build:sdk
|
||||
|
||||
- name: Lint and format
|
||||
run: |
|
||||
npm run lint:fix
|
||||
npm run format
|
||||
npm run lint
|
||||
|
||||
- name: Run unit tests
|
||||
run: npm run test
|
||||
|
||||
- name: Sync version
|
||||
run: node scripts/sync-version.cjs --version "${{ needs.prep.outputs.version }}"
|
||||
|
||||
- name: Commit changes to dev branch
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
if git diff --quiet; then
|
||||
echo "No lint/format/version changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${{ needs.prep.outputs.mode }}" = "Dry run" ]; then
|
||||
echo "DRY RUN: would commit and push the following changes to ${{ needs.prep.outputs.dev_branch }}:"
|
||||
git --no-pager diff --stat
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git add -A
|
||||
git commit -m "chore: lint, format, and bump version to ${{ needs.prep.outputs.version }}"
|
||||
git push origin HEAD:"${{ needs.prep.outputs.dev_branch }}"
|
||||
|
||||
sync-main:
|
||||
needs: [prep, normalize]
|
||||
if: ${{ needs.prep.outputs.channel == 'Stable' && needs.prep.outputs.mode != 'Dry run' && needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout dev branch
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.prep.outputs.dev_branch }}
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.TERMIX_PAT }}
|
||||
|
||||
- name: Merge main into dev branch
|
||||
run: |
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
git fetch origin main
|
||||
# -X ours leaves modify/delete conflicts, so settle those to the dev side too
|
||||
if ! git merge origin/main -X ours --no-edit; then
|
||||
git diff --name-only --diff-filter=U | while read -r f; do
|
||||
if git cat-file -e "HEAD:$f" 2>/dev/null; then
|
||||
git checkout --ours -- "$f" && git add -- "$f"
|
||||
else
|
||||
git rm -q -- "$f"
|
||||
fi
|
||||
done
|
||||
git commit --no-edit
|
||||
fi
|
||||
git push origin HEAD:"${{ needs.prep.outputs.dev_branch }}"
|
||||
|
||||
merge-to-main:
|
||||
needs: [prep, translate, normalize, sync-main]
|
||||
if: ${{ always() && needs.prep.result == 'success' && needs.prep.outputs.channel == 'Stable' && (needs.translate.result == 'success' || needs.translate.result == 'skipped') && (needs.normalize.result == 'success' || needs.normalize.result == 'skipped') && (needs.sync-main.result == 'success' || needs.sync-main.result == 'skipped') }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
outputs:
|
||||
main_sha: ${{ steps.merge.outputs.main_sha }}
|
||||
build_ref: ${{ steps.merge.outputs.build_ref }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Generate PR body
|
||||
id: body
|
||||
run: |
|
||||
node scripts/generate-release-body.cjs \
|
||||
--version "${{ needs.prep.outputs.version }}" \
|
||||
--mobile-version "${{ needs.prep.outputs.mobile_version }}" \
|
||||
--mobile-tag "${{ needs.prep.outputs.mobile_tag }}" > PR_BODY.md
|
||||
|
||||
- name: Open and squash-merge PR to main
|
||||
id: merge
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
DEV_BRANCH="${{ needs.prep.outputs.dev_branch }}"
|
||||
TITLE="v${{ needs.prep.outputs.version }}"
|
||||
|
||||
if [ "${{ needs.prep.outputs.mode }}" = "Overwrite release" ]; then
|
||||
echo "OVERWRITE: no merge; building from main as-is."
|
||||
echo "build_ref=main" >> "$GITHUB_OUTPUT"
|
||||
echo "main_sha=$(gh api repos/${{ github.repository }}/commits/main -q .sha)" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${{ needs.prep.outputs.mode }}" = "Dry run" ]; then
|
||||
echo "DRY RUN: would open and squash-merge a PR from $DEV_BRANCH into main."
|
||||
echo "DRY RUN: downstream jobs will build from $DEV_BRANCH instead of main."
|
||||
echo "build_ref=$DEV_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "main_sha=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --head "$DEV_BRANCH" --base main --state open --json number -q '.[0].number' || true)
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
PR_NUMBER=$(gh pr create --repo ${{ github.repository }} \
|
||||
--base main --head "$DEV_BRANCH" \
|
||||
--title "$TITLE" --body-file PR_BODY.md \
|
||||
| grep -oE '[0-9]+$')
|
||||
fi
|
||||
|
||||
gh pr merge "$PR_NUMBER" --repo ${{ github.repository }} --squash --admin
|
||||
|
||||
STATE=$(gh pr view "$PR_NUMBER" --repo ${{ github.repository }} --json state -q .state)
|
||||
if [ "$STATE" != "MERGED" ]; then
|
||||
echo "PR #$PR_NUMBER did not merge (state: $STATE)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MAIN_SHA=$(gh api repos/${{ github.repository }}/commits/main -q .sha)
|
||||
echo "main_sha=$MAIN_SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "build_ref=$MAIN_SHA" >> "$GITHUB_OUTPUT"
|
||||
|
||||
docker:
|
||||
needs: [prep, translate, verify-beta, merge-to-main]
|
||||
if: ${{ always() && needs.prep.result == 'success' && needs.prep.outputs.skip != 'true' && (needs.merge-to-main.result == 'success' || needs.verify-beta.result == 'success') }}
|
||||
uses: ./.github/workflows/docker.yml
|
||||
with:
|
||||
version: ${{ needs.prep.outputs.version }}
|
||||
build_type: ${{ needs.prep.outputs.channel == 'Beta' && 'Beta' || 'Production' }}
|
||||
dry_run: ${{ needs.prep.outputs.mode == 'Dry run' }}
|
||||
source_ref: ${{ needs.merge-to-main.outputs.build_ref || needs.translate.outputs.sha || needs.prep.outputs.sha }}
|
||||
secrets: inherit
|
||||
|
||||
create-release:
|
||||
needs: [prep, merge-to-main, docker]
|
||||
if: ${{ always() && needs.prep.outputs.channel == 'Stable' && needs.docker.result == 'success' && needs.prep.outputs.mode != 'Dry run' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Clear existing release artifacts (overwrite mode)
|
||||
if: ${{ needs.prep.outputs.mode == 'Overwrite release' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
TAG="${{ needs.prep.outputs.release_tag }}"
|
||||
if ! gh release view "$TAG" --repo ${{ github.repository }} >/dev/null 2>&1; then
|
||||
echo "Overwrite release: no existing release $TAG to overwrite."
|
||||
exit 1
|
||||
fi
|
||||
echo "Clearing existing assets from $TAG..."
|
||||
gh release view "$TAG" --repo ${{ github.repository }} --json assets -q '.assets[].name' | while read -r ASSET; do
|
||||
[ -n "$ASSET" ] && gh release delete-asset "$TAG" "$ASSET" --repo ${{ github.repository }} --yes || true
|
||||
done
|
||||
|
||||
- name: Generate release body
|
||||
if: ${{ needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
run: |
|
||||
node scripts/generate-release-body.cjs \
|
||||
--version "${{ needs.prep.outputs.version }}" \
|
||||
--mobile-version "${{ needs.prep.outputs.mobile_version }}" \
|
||||
--mobile-tag "${{ needs.prep.outputs.mobile_tag }}" > RELEASE_BODY.md
|
||||
|
||||
- name: Create or update GitHub release
|
||||
if: ${{ needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
TAG="${{ needs.prep.outputs.release_tag }}"
|
||||
TITLE="Termix v${{ needs.prep.outputs.version }}"
|
||||
if gh release view "$TAG" --repo ${{ github.repository }} >/dev/null 2>&1; then
|
||||
gh release edit "$TAG" --repo ${{ github.repository }} --title "$TITLE" --notes-file RELEASE_BODY.md
|
||||
else
|
||||
gh release create "$TAG" --repo ${{ github.repository }} --title "$TITLE" --notes-file RELEASE_BODY.md --target "${{ needs.merge-to-main.outputs.main_sha }}"
|
||||
fi
|
||||
|
||||
create-beta-release:
|
||||
needs: [prep, translate, docker]
|
||||
if: ${{ always() && needs.prep.outputs.channel == 'Beta' && needs.docker.result == 'success' && needs.prep.outputs.mode != 'Dry run' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout beta commit
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.translate.outputs.sha || needs.prep.outputs.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Generate beta release body
|
||||
run: |
|
||||
node scripts/generate-beta-body.cjs \
|
||||
--version "${{ needs.prep.outputs.version }}" \
|
||||
--branch "${{ needs.prep.outputs.dev_branch }}" \
|
||||
--sha "${{ needs.translate.outputs.sha || needs.prep.outputs.sha }}" \
|
||||
--prev "${{ needs.prep.outputs.prev_ref }}" > BETA_BODY.md
|
||||
|
||||
- name: Create beta release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
VERSION="${{ needs.prep.outputs.version }}"
|
||||
TITLE="Termix v${VERSION%-beta.*} Beta ${VERSION##*-beta.}"
|
||||
TAG="${{ needs.prep.outputs.release_tag }}"
|
||||
if gh release view "$TAG" --repo ${{ github.repository }} >/dev/null 2>&1; then
|
||||
gh release edit "$TAG" --repo ${{ github.repository }} \
|
||||
--title "$TITLE" --notes-file BETA_BODY.md --prerelease
|
||||
else
|
||||
gh release create "$TAG" --repo ${{ github.repository }} \
|
||||
--title "$TITLE" --notes-file BETA_BODY.md \
|
||||
--prerelease --target "${{ needs.translate.outputs.sha || needs.prep.outputs.sha }}"
|
||||
fi
|
||||
|
||||
electron-release:
|
||||
needs:
|
||||
[
|
||||
prep,
|
||||
translate,
|
||||
merge-to-main,
|
||||
docker,
|
||||
create-release,
|
||||
create-beta-release,
|
||||
]
|
||||
if: ${{ always() && needs.prep.outputs.skip != 'true' && needs.docker.result == 'success' && needs.create-release.result != 'failure' && needs.create-beta-release.result != 'failure' }}
|
||||
uses: ./.github/workflows/electron.yml
|
||||
with:
|
||||
build_type: all
|
||||
artifact_destination: ${{ needs.prep.outputs.mode == 'Dry run' && 'file' || 'release' }}
|
||||
release_tag: ${{ needs.prep.outputs.release_tag }}
|
||||
version_override: ${{ needs.prep.outputs.channel == 'Beta' && needs.prep.outputs.version || '' }}
|
||||
source_ref: ${{ needs.merge-to-main.outputs.build_ref || needs.translate.outputs.sha || needs.prep.outputs.sha }}
|
||||
secrets: inherit
|
||||
|
||||
electron-submit:
|
||||
needs: [prep, merge-to-main, electron-release]
|
||||
if: ${{ always() && needs.electron-release.result == 'success' && needs.prep.outputs.channel == 'Stable' && needs.prep.outputs.mode != 'Dry run' && needs.prep.outputs.mode != 'Skip submit' }}
|
||||
uses: ./.github/workflows/electron.yml
|
||||
with:
|
||||
build_type: all
|
||||
artifact_destination: submit
|
||||
source_ref: ${{ needs.merge-to-main.outputs.build_ref }}
|
||||
secrets: inherit
|
||||
|
||||
cask-commit-back:
|
||||
needs: [prep, electron-release]
|
||||
if: ${{ always() && needs.electron-release.result == 'success' && needs.prep.outputs.channel == 'Stable' && needs.prep.outputs.mode != 'Dry run' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 1
|
||||
token: ${{ secrets.TERMIX_PAT }}
|
||||
|
||||
- name: Bump and commit Homebrew cask
|
||||
env:
|
||||
VERSION: ${{ needs.prep.outputs.version }}
|
||||
DMG_SHA256: ${{ needs.electron-release.outputs.macos_universal_dmg_sha256 }}
|
||||
run: |
|
||||
if [ -z "$DMG_SHA256" ]; then
|
||||
echo "No universal DMG checksum available (macOS build unsigned or skipped); leaving cask unchanged."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
|
||||
git fetch origin main
|
||||
git checkout -B main origin/main
|
||||
|
||||
sed -i "s|version \".*\"|version \"$VERSION\"|g" Casks/termix.rb
|
||||
sed -i "s|sha256 \".*\"|sha256 \"$DMG_SHA256\"|g" Casks/termix.rb
|
||||
|
||||
git add Casks/termix.rb
|
||||
if git diff --cached --quiet; then
|
||||
echo "Cask already up to date."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git commit -m "chore: bump Homebrew cask to $VERSION"
|
||||
git push origin HEAD:main
|
||||
|
||||
prune-betas:
|
||||
needs: [prep, create-release]
|
||||
if: ${{ always() && needs.prep.outputs.channel == 'Stable' && needs.create-release.result == 'success' && needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Delete this version's beta releases (tags stay)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
PREFIX="v${{ needs.prep.outputs.version }}-beta."
|
||||
gh release list --repo ${{ github.repository }} --limit 200 --json tagName -q '.[].tagName' \
|
||||
| grep -F "$PREFIX" | while read -r TAG; do
|
||||
echo "Deleting release $TAG"
|
||||
gh release delete "$TAG" --repo ${{ github.repository }} --yes || true
|
||||
done
|
||||
|
||||
# The docs site reads the env catalog, API spec and download list from the
|
||||
# newest stable release.
|
||||
# Docs written for this release live on dev-X.Y.Z in the Docs repo. Squash
|
||||
# merge it into main once the release is out. No branch means nothing to do.
|
||||
docs-merge:
|
||||
needs: [prep, electron-release]
|
||||
if: ${{ always() && needs.prep.outputs.channel == 'Stable' && needs.electron-release.result == 'success' && needs.prep.outputs.mode != 'Dry run' && needs.prep.outputs.mode != 'Overwrite release' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Merge the docs dev branch into main
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
REPO: Termix-SSH/Docs
|
||||
VERSION: ${{ needs.prep.outputs.version }}
|
||||
run: |
|
||||
BRANCH="dev-$VERSION"
|
||||
if ! gh api "repos/$REPO/branches/$BRANCH" > /dev/null 2>&1; then
|
||||
echo "$REPO has no $BRANCH branch, nothing to merge."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
AHEAD=$(gh api "repos/$REPO/compare/main...$BRANCH" -q .ahead_by)
|
||||
if [ "$AHEAD" = "0" ]; then
|
||||
echo "$BRANCH has nothing main doesn't, deleting it."
|
||||
gh api -X DELETE "repos/$REPO/git/refs/heads/$BRANCH"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PR_NUMBER=$(gh pr list --repo "$REPO" --head "$BRANCH" --base main --state open --json number -q '.[0].number')
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
PR_NUMBER=$(gh pr create --repo "$REPO" --base main --head "$BRANCH" \
|
||||
--title "v$VERSION" --body "Docs for Termix v$VERSION." | grep -oE '[0-9]+$')
|
||||
fi
|
||||
|
||||
gh pr merge "$PR_NUMBER" --repo "$REPO" --squash --admin --delete-branch
|
||||
|
||||
STATE=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json state -q .state)
|
||||
if [ "$STATE" != "MERGED" ]; then
|
||||
echo "Docs PR #$PR_NUMBER did not merge (state: $STATE)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docs-refresh:
|
||||
needs: [prep, electron-release, docs-merge]
|
||||
if: ${{ always() && needs.prep.outputs.channel == 'Stable' && needs.electron-release.result == 'success' && needs.prep.outputs.mode != 'Dry run' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Tell the docs site
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: gh api repos/Termix-SSH/Docs/dispatches -f event_type=core-released
|
||||
|
||||
cleanup:
|
||||
needs: [prep, merge-to-main, electron-release, cask-commit-back]
|
||||
if: ${{ always() && needs.prep.outputs.channel == 'Stable' && (needs.prep.outputs.mode == 'Everything' || needs.prep.outputs.mode == 'Skip submit') && needs.merge-to-main.result == 'success' }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Delete dev branch in Termix
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TERMIX_PAT }}
|
||||
run: |
|
||||
git push https://x-access-token:${{ secrets.TERMIX_PAT }}@github.com/${{ github.repository }}.git \
|
||||
--delete "${{ needs.prep.outputs.dev_branch }}" || true
|
||||
@@ -1,53 +0,0 @@
|
||||
name: Translate
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
retranslate:
|
||||
description: "Translate every string again, not only new or changed ones"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: translate-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
translate:
|
||||
if: ${{ startsWith(github.ref, 'refs/heads/dev-') }}
|
||||
runs-on: blacksmith-2vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 1
|
||||
token: ${{ secrets.TERMIX_PAT }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Translate
|
||||
uses: Termix-SSH/Termix-Registry/translate@main
|
||||
with:
|
||||
source: src/ui/locales/en.json
|
||||
out: src/ui/locales/translated
|
||||
languages: src/ui/locales/languages.json
|
||||
retranslate: ${{ inputs.retranslate }}
|
||||
api-key: ${{ secrets.TERMIX_LLM_API_KEY }}
|
||||
|
||||
- name: Commit translations
|
||||
run: |
|
||||
git add src/ui/locales
|
||||
if git diff --cached --quiet; then
|
||||
echo "No translation changes."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "LukeGus"
|
||||
git config user.email "bugattiguy527@gmail.com"
|
||||
git commit -m "chore: update translations"
|
||||
git push origin HEAD:"${GITHUB_REF_NAME}"
|
||||
+5
-27
@@ -1,3 +1,4 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
@@ -7,41 +8,18 @@ pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
src/mcp-server/node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
# Plugin build output. termix-plugin build writes it, the packaged server
|
||||
# gets its copy under dist/plugins.
|
||||
*.tmxplug
|
||||
*.tmxplug.sig
|
||||
termix-plugin-signing.key
|
||||
/src/**/*.js
|
||||
|
||||
.vscode/
|
||||
.idea/
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
/db/
|
||||
/release/
|
||||
/.claude/
|
||||
/ssl/
|
||||
/uploads/
|
||||
/nul
|
||||
.env
|
||||
electron/build-info.cjs
|
||||
/.mcp.json
|
||||
/CLAUDE.md
|
||||
/old_db/
|
||||
/scripts/auto-fix.mjs
|
||||
/scripts/auto-fix-blocklist.json
|
||||
/scripts/auto-fix-state.json
|
||||
/scripts/auto-fix-report-*.json
|
||||
@@ -1 +0,0 @@
|
||||
npx --no -- commitlint --edit "$1"
|
||||
@@ -1,3 +0,0 @@
|
||||
# The .cmd shims on Windows add their own paths to each command, so keep
|
||||
# lint-staged's chunks well under cmd.exe's 8191 character limit.
|
||||
npx lint-staged --max-arg-length 4000
|
||||
@@ -1,14 +0,0 @@
|
||||
build
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
||||
package-lock.json
|
||||
|
||||
dist-ssr
|
||||
release
|
||||
db
|
||||
*.min.js
|
||||
*.min.css
|
||||
openapi.json
|
||||
drizzle/
|
||||
src/ui/settings/settings-search-index.ts
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 80,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## 26.10.1
|
||||
|
||||
### Added
|
||||
|
||||
- Slovak, Croatian, Slovenian, Lithuanian, Latvian, Estonian and Malay
|
||||
- The desktop app can update itself. Pick Automatic, Ask first or Never in Settings, Updates. Store and package manager installs keep updating the way they do now
|
||||
- Community plugins. Turn on the community registry in Plugins, Registries to browse and install plugins made by other people, each version reviewed before it is listed
|
||||
- Custom plugin registries. Add your own registry by its index URL; its signing key is pinned when you add it
|
||||
|
||||
### Changed
|
||||
|
||||
- Every language is now fully translated, in Termix and in every plugin, and stays up to date with each release
|
||||
- Languages with more than two plural forms, like Russian, Polish and Arabic, now use the right one
|
||||
|
||||
### Fixed
|
||||
|
||||
- Regional browser languages like `es-MX`, `pt` or `zh-HK` showed English instead of the closest translation
|
||||
- Counts like "1 keys" or "Moved 1 host(s)" now use the singular
|
||||
- Plugin updates synced to the desktop app failed to start with "Cannot find package"
|
||||
- The desktop app showed plugins that only run on the server as not running and out of date
|
||||
|
||||
## 26.10.0
|
||||
|
||||
### Added
|
||||
|
||||
- Plugins. Every feature beyond hosts, credentials and sharing is now its own plugin with its own repo, and you pick which ones you want
|
||||
- A Plugins tab to install, update, pin, turn off and remove plugins from the official registry, with release notes and a beta channel per plugin
|
||||
- Developer mode to install a plugin from a file, and a plugin SDK on npm to build your own
|
||||
- The community plugin registry is open for submissions. Termix can install community plugins in a later update
|
||||
- Redesigned UI with a Manage tab for hosts and credentials and a Settings tab with search
|
||||
- New full screen onboarding where you choose which plugins to start with
|
||||
- Beta channel for Termix itself in Settings > Updates
|
||||
- Docs links on every settings page, in the Plugins tab, in plugin settings and in the command palette
|
||||
- Plugins can link their own docs and list the environment variables they read, shown on their page in the Plugins tab
|
||||
- Report a bug links that open a prefilled issue in the right repo
|
||||
- `TRUSTED_PROXIES` to choose which proxies nginx takes client IPs from
|
||||
|
||||
### Changed
|
||||
|
||||
- Termix now uses calendar versions (year, month, patch), starting with 26.10.0
|
||||
- Redesigned host defaults with admin, user and folder levels
|
||||
- Simpler host status: online or offline, kept live without a refresh
|
||||
- Bug reports and feature requests now go to each repo instead of the Support repo
|
||||
|
||||
### Fixed
|
||||
|
||||
- A lot of bugs across the app, the desktop app and every plugin
|
||||
- Several security issues reported through GitHub advisories
|
||||
|
||||
### Removed
|
||||
|
||||
- Downgrading to 2.8 is no longer supported. A 2.8 install has to start 2.9 once before upgrading
|
||||
- The donation reminder popup
|
||||
@@ -1,75 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
Termix is a small core plus plugins. This repo is the core: hosts, credentials, users, sharing, sessions, the app shell and the plugin runtime. Every other feature lives in its own `Plugin-<Name>` repo. If your change is about the terminal, file manager, Docker or any other plugin feature, open it in that plugin's repo instead.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Node.js](https://nodejs.org/en/download/) 22.12 or newer (built with v24)
|
||||
- [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone the repository:
|
||||
```sh
|
||||
git clone https://github.com/Termix-SSH/Termix
|
||||
```
|
||||
2. Install the dependencies:
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
## Running the development server
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
This builds everything, starts the backend and then the Vite server at `http://localhost:5173/`. Backend changes restart the backend, and plugin changes in `../Termix-Plugins` rebuild and reload that plugin. `npm run dev:electron` does the same with the desktop app, and `npm run dev -- --help` lists the other options.
|
||||
|
||||
## Useful commands
|
||||
|
||||
```sh
|
||||
npm run test # run the test suite
|
||||
npm run type-check # type-check the core
|
||||
npm run lint # lint and the other repo checks
|
||||
npm run format # format the code with Prettier
|
||||
```
|
||||
|
||||
## Making a change
|
||||
|
||||
1. **Fork the repository**: Click "Fork" at the top right of the [repository page](https://github.com/Termix-SSH/Termix).
|
||||
2. **Create a branch**:
|
||||
```sh
|
||||
git checkout -b feature/my-new-feature
|
||||
```
|
||||
3. **Make your changes** and add or update tests for them.
|
||||
4. **Commit your changes**:
|
||||
```sh
|
||||
git commit -m "feat: add my new feature"
|
||||
```
|
||||
5. **Push to your fork**:
|
||||
```sh
|
||||
git push origin feature/my-new-feature
|
||||
```
|
||||
6. **Open a pull request** against the current `dev-*` branch with a clear description.
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Follow the existing code style. The frontend uses React, Tailwind CSS and shadcn components in `src/ui/`.
|
||||
- Never hardcode text. Use `t()` and add the English string to `src/ui/locales/en.json`. That's the only locale file you need to update. Other languages are translated automatically, and if an automatic translation is wrong you can fix it in that language's file.
|
||||
- Keep the UI flat and square. Avoid rounded corners on panels, cards and dialogs.
|
||||
- Use the theme variables (like `var(--bg-base)` and `var(--text-primary)`) instead of fixed colors.
|
||||
- There is one component tree for desktop and mobile. Use `src/ui/hooks/use-mobile.ts` for layout changes.
|
||||
- Core never names a plugin. If core needs something from a plugin, add a slot, action or component id that the plugin fills.
|
||||
- Tests live in `src/backend/tests/` and `src/ui/tests/`, mirroring the source tree. `npm run test` must pass.
|
||||
- Every API route gets an OpenAPI JSDoc comment like the routes around it.
|
||||
- Use short commit messages that start with `feat:`, `fix:` or `chore:`, and link related issues.
|
||||
|
||||
## Building a plugin
|
||||
|
||||
Start from the [plugin template](https://github.com/Termix-SSH/Termix-Plugin-Template). It talks to Termix only through `@termix-ssh/plugin-sdk` and has its own build, test and release setup.
|
||||
|
||||
## Support
|
||||
|
||||
Bugs and ideas for Termix itself go in [this repo](https://github.com/Termix-SSH/Termix/issues/new/choose). Plugin problems go in that plugin's own `Plugin-<Name>` repo. Please be as detailed as possible, preferably in English. You can also ask in the [Discord](https://discord.gg/jVQGdvHDrf) server.
|
||||
@@ -1,26 +0,0 @@
|
||||
cask "termix" do
|
||||
version "26.10.0"
|
||||
sha256 "66a76a62fbea3306bdf35b0951e9b1200fd1a084a95b4fee9d40edd6e326e11a"
|
||||
|
||||
url "https://github.com/Termix-SSH/Termix/releases/download/v#{version}/termix_macos_universal_dmg.dmg"
|
||||
name "Termix"
|
||||
desc "Self-hosted, plugin-based server management"
|
||||
homepage "https://github.com/Termix-SSH/Termix"
|
||||
|
||||
livecheck do
|
||||
url :url
|
||||
strategy :github_latest
|
||||
end
|
||||
|
||||
auto_updates true
|
||||
|
||||
app "Termix.app"
|
||||
|
||||
zap trash: [
|
||||
"~/Library/Application Support/termix",
|
||||
"~/Library/Caches/com.karmaa.termix",
|
||||
"~/Library/Caches/com.karmaa.termix.ShipIt",
|
||||
"~/Library/Preferences/com.karmaa.termix.plist",
|
||||
"~/Library/Saved Application State/com.karmaa.termix.savedState",
|
||||
]
|
||||
end
|
||||
@@ -1,203 +1,13 @@
|
||||
Copyright 2026 Luke Gustafson
|
||||
Copyright 2025 Luke Gustafson
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,146 +1,52 @@
|
||||
<div align="center">
|
||||
# Repo Stats
|
||||

|
||||

|
||||

|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720"></a>
|
||||
#### Top Technologies
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
|
||||
<img src="./public/icon.svg" width="120" height="120" alt="Termix Logo" />
|
||||
|
||||
<h1>Termix</h1>
|
||||
|
||||
<p>Self-hosted, plugin-based server management</p>
|
||||
|
||||
<p>
|
||||
<img src="https://img.shields.io/github/stars/Termix-SSH/Termix?style=flat&label=Stars&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/forks/Termix-SSH/Termix?style=flat&label=Forks&color=F39044&labelColor=1a1a1a" />
|
||||
<img src="https://img.shields.io/github/v/release/Termix-SSH/Termix?style=flat&label=Release&color=F39044&labelColor=1a1a1a&v=1" />
|
||||
<a href="https://discord.gg/jVQGdvHDrf"><img alt="Discord" src="https://img.shields.io/discord/1347374268253470720?color=F39044&labelColor=1a1a1a" /></a>
|
||||
<a href="https://donate.termix.site/"><img alt="Donate" src="https://img.shields.io/badge/Donate-Support%20Termix-F39044?style=flat&labelColor=1a1a1a" /></a>
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/LukeGus/Termix">
|
||||
<img alt="Termix Banner" src=./public/icon.svg style="width: 250px; height: auto;"> </a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://donate.termix.site/"><img alt="Donations this month" src="https://img.shields.io/badge/dynamic/json?style=for-the-badge&label=Donations%20this%20month&query=%24.fiatTotal&prefix=%24&url=https%3A%2F%2Ftermix.site%2Fdonation-snapshot.json&color=F39044&labelColor=1a1a1a" /></a>
|
||||
</p>
|
||||
If you would like, you can support the project here!\
|
||||
[](https://github.com/sponsors/LukeGus)
|
||||
|
||||
</div>
|
||||
# Overview
|
||||
Termix is an open-source, forever-free, self-hosted all-in-one server management platform. It provides a web-based solution for managing your servers and infrastructure through a single, intuitive interface. Termix offers SSH terminal access, SSH tunneling capabilities, and remote file configuration editing, with many more tools to come.
|
||||
|
||||
<br />
|
||||
# Features
|
||||
- **SSH Terminal Access** - Full-featured terminal with split-screen support (up to 4 panels) and tab system
|
||||
- **SSH Tunnel Management** - Create and manage SSH tunnels with automatic reconnection and health monitoring
|
||||
- **Remote Config Editor** - Edit files directly on remote servers with syntax highlighting and file management
|
||||
- **SSH Host Manager** - Save, organize, and manage your SSH connections with tags and folders
|
||||
- **User Authentication** - Secure user management with admin controls
|
||||
- **Modern UI** - Clean interface built with React, Tailwind CSS, and the amazing Shadcn
|
||||
|
||||
## Overview
|
||||
|
||||
Termix is a free, open source, self-hosted platform for managing your servers, built on plugins. The core is small. It keeps your hosts, credentials, users, sharing and sessions. Everything else, like the SSH terminal, remote desktop, file manager, Docker and metrics, is a plugin you can turn on, turn off or remove.
|
||||
|
||||
It runs on web, desktop and mobile, and it is a self-hosted alternative to Termius that stays free forever.
|
||||
|
||||
<br />
|
||||
|
||||
## Try the Demo
|
||||
|
||||
Want to see it before you install it? Try the demo at [demo.termix.site](https://demo.termix.site/). Any username and password works.
|
||||
|
||||
<br />
|
||||
|
||||
## Core
|
||||
|
||||
What every Termix install has, with or without plugins:
|
||||
|
||||
- **Hosts:** Save hosts in nested folders with tags and parent hosts, bulk edit, import and export, and use Quick Connect for one-off connections
|
||||
- **Credentials:** Reuse saved passwords and keys across hosts, with host defaults you can set for the server, a user or a folder
|
||||
- **Sharing and Roles:** Share hosts, credentials and folders with users or roles at four levels: connect, view, edit and manage
|
||||
- **Accounts:** Local accounts, sessions you can see and revoke, trusted devices, API keys and an audit log
|
||||
- **Security:** Passwords, keys and other secrets are encrypted per user, and the database can be encrypted on disk
|
||||
- **Desktop Sync:** The desktop app runs on its own and can link to a Termix server to keep an offline copy of your account
|
||||
- **Interface:** Tabs and split screen, a command palette (double tap left shift), rebindable shortcuts, themes, branding and around 30 languages
|
||||
- **Databases:** SQLite by default, with PostgreSQL and MySQL supported too
|
||||
|
||||
<br />
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugins add everything else. The official ones ship with Termix, and admins can install, update or remove plugins from the Plugins tab. Each plugin has its own repo.
|
||||
|
||||
| Plugin | What it does |
|
||||
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| [ACME Certificates](https://github.com/Termix-SSH/Plugin-ACME-SSL) | Gets the Termix HTTPS certificate from Let's Encrypt or any ACME provider and renews it for you. |
|
||||
| [AI Assistant](https://github.com/Termix-SSH/Plugin-AI) | An AI assistant that reads your setup and proposes changes for you to approve. |
|
||||
| [Alerts](https://github.com/Termix-SSH/Plugin-Alerts) | One inbox for every alert in Termix, with delivery to webhooks, ntfy, Discord and email. |
|
||||
| [Automations](https://github.com/Termix-SSH/Plugin-Automations) | Run steps on your hosts on a schedule or when something happens. |
|
||||
| [Docker](https://github.com/Termix-SSH/Plugin-Docker) | Manage Docker and Podman containers on your hosts over SSH, with logs, stats and a console. |
|
||||
| [File Manager](https://github.com/Termix-SSH/Plugin-File-Manager) | Browse, edit and move files over SFTP, including straight from one server to another. |
|
||||
| [Fleets](https://github.com/Termix-SSH/Plugin-Fleets) | Group hosts into fleets and run commands, package actions and file transfers on all of them at once. |
|
||||
| [HashiCorp Vault](https://github.com/Termix-SSH/Plugin-Vault) | Connect to hosts with short-lived SSH certificates signed by HashiCorp Vault. |
|
||||
| [Homepage](https://github.com/Termix-SSH/Plugin-Homepage) | A drag and drop widget page for your servers and services, plus service links for the dashboard. |
|
||||
| [Host Metrics](https://github.com/Termix-SSH/Plugin-Host-Metrics) | Live CPU, memory, disk, network and GPU stats, plus tools to manage your hosts. |
|
||||
| [LDAP](https://github.com/Termix-SSH/Plugin-LDAP) | Sign in with your LDAP or Active Directory username and password. |
|
||||
| [Network Topology](https://github.com/Termix-SSH/Plugin-Network-Topology) | Draws your hosts and the links between them as a live, interactive graph. |
|
||||
| [OPKSSH](https://github.com/Termix-SSH/Plugin-OPKSSH) | Connect to hosts with short-lived OpenPubkey SSH certificates after signing in with your identity provider. |
|
||||
| [Passkeys](https://github.com/Termix-SSH/Plugin-WebAuthn) | Sign in with a passkey or security key instead of a password. |
|
||||
| [Proxmox](https://github.com/Termix-SSH/Plugin-Proxmox) | Import Proxmox VE guests as hosts, keep them in sync and watch node stats. |
|
||||
| [Remote Desktop](https://github.com/Termix-SSH/Plugin-Remote-Desktop) | RDP, VNC and Telnet sessions in your browser, with clipboard, file transfer, sharing and recording. |
|
||||
| [Secret Sources](https://github.com/Termix-SSH/Plugin-Secret-Sources) | Pull host passwords and keys from 1Password when you connect instead of storing them in Termix. |
|
||||
| [Serial](https://github.com/Termix-SSH/Plugin-Serial) | Open a serial console to a router, switch or other device plugged into your computer. |
|
||||
| [Session Recording](https://github.com/Termix-SSH/Plugin-Session-Recording) | Record terminal and remote desktop sessions and play them back or download them later. |
|
||||
| [Session Sharing](https://github.com/Termix-SSH/Plugin-Session-Sharing) | Share live sessions by link or with another user, and present sessions to a group in meeting rooms. |
|
||||
| [Single sign-on](https://github.com/Termix-SSH/Plugin-SSO) | Sign in with any OpenID Connect provider, GitHub or Google. |
|
||||
| [Snippets](https://github.com/Termix-SSH/Plugin-Snippets) | Save the commands you run often and run them in a terminal or on many hosts in one click. |
|
||||
| [SSH Terminal](https://github.com/Termix-SSH/Plugin-SSH-Terminal) | SSH terminal sessions with tabs, split screen, history, macros and a local terminal in the desktop app. |
|
||||
| [Step CA](https://github.com/Termix-SSH/Plugin-Step-CA) | Connect to hosts with short-lived SSH certificates from a smallstep step-ca server. |
|
||||
| [Tailscale](https://github.com/Termix-SSH/Plugin-Tailscale) | Add tailnet devices as hosts and connect with Tailscale SSH. |
|
||||
| [Termix Identity](https://github.com/Termix-SSH/Plugin-Termix-Identity) | Publish your SSH public keys under a public handle and run your own SSH certificate authority. |
|
||||
| [Tmux Monitor](https://github.com/Termix-SSH/Plugin-Tmux-Monitor) | Browse and control tmux sessions, windows and panes across your hosts. |
|
||||
| [TOTP](https://github.com/Termix-SSH/Plugin-TOTP) | Two-factor sign in with a code from an authenticator app, with backup codes. |
|
||||
| [Tunnels](https://github.com/Termix-SSH/Plugin-Tunnels) | SSH port forwarding that reconnects on its own, plus client tunnels from the desktop app. |
|
||||
| [Usage Statistics](https://github.com/Termix-SSH/Plugin-Telemetry) | Sends a small anonymous daily report so we can see how Termix is used. |
|
||||
| [Wake-on-LAN](https://github.com/Termix-SSH/Plugin-Wake-On-LAN) | Wake sleeping machines by sending a Wake-on-LAN packet to their MAC address. |
|
||||
| [Warpgate](https://github.com/Termix-SSH/Plugin-Warpgate) | Connect to hosts through a Warpgate SSH bastion. |
|
||||
| [Web Endpoint](https://github.com/Termix-SSH/Plugin-Web-Endpoint) | Open a host's web UI inside Termix, directly or over an SSH tunnel. |
|
||||
| [Workspaces](https://github.com/Termix-SSH/Plugin-Workspaces) | Save your open tabs and split layouts and reopen them in one click. |
|
||||
|
||||
Want to build your own? Start from the [plugin template](https://github.com/Termix-SSH/Termix-Plugin-Template). Plugins you can install are listed in the [registry](https://github.com/Termix-SSH/Termix-Registry). Turn on the community registry in Plugins, Registries to install plugins made by other people, or add your own registry. See [submitting a plugin](https://docs.termix.site/develop/community-registry) and [hosting your own registry](https://docs.termix.site/develop/registries#host-your-own-registry).
|
||||
|
||||
<br />
|
||||
|
||||
## Platform Support
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<th align="center">Platform</th>
|
||||
<th align="center">Distribution</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Web</b></td>
|
||||
<td>Any modern browser (Chrome, Safari, Firefox) | PWA support</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Windows</b> <sub>x64/ia32</sub></td>
|
||||
<td>Portable | EXE and MSI Installer | Chocolatey</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Linux</b> <sub>x64/arm64/armv7l</sub></td>
|
||||
<td>Portable | AUR | AppImage | Deb | Flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>macOS</b> <sub>Universal/x64/arm64, v12.0+</sub></td>
|
||||
<td>Apple App Store | DMG | Homebrew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>iOS/iPadOS</b> <sub>v15.1+</sub></td>
|
||||
<td>Apple App Store | IPA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><b>Android</b> <sub>v7.0+</sub></td>
|
||||
<td>Google Play Store | APK</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
## Installation
|
||||
|
||||
Visit the [Termix Docs](https://docs.termix.site/install) for full install steps on every platform.
|
||||
|
||||
Sample Docker Compose file (you can leave out `guacd` and the network if you don't plan to use the Remote Desktop plugin):
|
||||
# Planned Features
|
||||
- **Improved Admin Control** - Ability to manage admins, and give more fine-grained control over their permissions, share hosts, reset passwords, delete accounts, etc
|
||||
- **More auth types** - Add 2FA, OCID support, etc
|
||||
- **Theming** - Modify themeing for all tools
|
||||
- **Improved SFTP Support** - Ability to manage files easier with the config editor by uploading, creating, and removing files
|
||||
- **Improved Terminal Support** - Add more terminal protocols such as VNC and RDP (anyone who has experience in integrating RDP into a web-application similar to Apache Guacamole, please contact me by creating an issue)
|
||||
|
||||
# Installation
|
||||
Visit the Termix [Docs](https://docs.termix.site/docs) for more information on how to install Termix. Otherwise, view a sample docker-compose file here:
|
||||
```yaml
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/termix-ssh/termix:latest
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -149,105 +55,33 @@ services:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
GUACD_HOST: "guacd"
|
||||
GUACD_TUNNEL_HOST: "termix"
|
||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||
GUACD_DRIVE_PATH: "/termix-data/rdp-drive"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- termix-data:/termix-data
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
driver: local
|
||||
```
|
||||
|
||||
### Cloud Hosting
|
||||
# Support
|
||||
If you need help with Termix, you can join the [Discord](https://discord.gg/jVQGdvHDrf) server and visit the support channel. You can also open an issue or open a pull request on the [GitHub](https://github.com/LukeGus/Termix/issues) repo.
|
||||
|
||||
You can run Termix on a VPS instead of inside your own network. If Termix runs on the network it manages, an outage takes Termix down with it, right when you need it to fix things. Running it somewhere else keeps it reachable, gives you a static IP and lets you get in from anywhere without a VPN or port forward.
|
||||
# Show-off
|
||||
|
||||
[GINERNET](https://docs.termix.site/install/ginernet) sponsors Termix, and the docs have a step by step guide for their VPS platform.
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 1.png" width="400" alt="Termix Demo 1"/>
|
||||
<img src="./repo-images/Image 2.png" width="400" alt="Termix Demo 2"/>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<p align="center">
|
||||
<img src="./repo-images/Image 3.png" width="250" alt="Termix Demo 3"/>
|
||||
<img src="./repo-images/Image 4.png" width="250" alt="Termix Demo 4"/>
|
||||
<img src="./repo-images/Image 5.png" width="250" alt="Termix Demo 5"/>
|
||||
</p>
|
||||
|
||||
## Donate
|
||||
<p align="center">
|
||||
<video src="https://github.com/user-attachments/assets/0f95495d-c5db-48f5-b18b-9ab48bb10d31" width="800" controls>
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</p>
|
||||
|
||||
Termix is free and open source with no subscriptions or paid plans. If you find it useful, consider donating to help cover server costs, domains and development time.
|
||||
|
||||
[Donate](https://donate.termix.site/)
|
||||
|
||||
<br />
|
||||
|
||||
## Sponsors
|
||||
|
||||
Interested in a paid placement to support development? Email [mail@termix.site](mailto:mail@termix.site).
|
||||
|
||||
<!-- SPONSORS:START -->
|
||||
|
||||
<div align="center">
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://www.blacksmith.sh/">
|
||||
<img src="https://termix.site/img/sponsors/blacksmith.svg" height="40" alt="Blacksmith" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.cloudflare.com/">
|
||||
<img src="https://termix.site/img/sponsors/cloudflare.png" height="40" alt="Cloudflare" />
|
||||
</a>
|
||||
|
||||
<a href="https://akamai.com/">
|
||||
<img src="https://termix.site/img/sponsors/akamai.svg" height="40" alt="Akamai" />
|
||||
</a>
|
||||
|
||||
<a href="https://aws.amazon.com/">
|
||||
<img src="https://termix.site/img/sponsors/aws.png" height="40" alt="AWS" />
|
||||
</a>
|
||||
|
||||
<a href="https://rackgenius.com/">
|
||||
<img src="https://termix.site/img/sponsors/rackgenius.png" height="40" alt="Rack Genius" />
|
||||
</a>
|
||||
|
||||
<a href="https://ginernet.com/">
|
||||
<img src="https://termix.site/img/sponsors/ginernet.png" height="40" alt="Ginernet" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.hetzner.com/?mtm_campaign=termix&mtm_medium=referral&mtm_content=sponsoring_link">
|
||||
<img src="https://termix.site/img/sponsors/hetzner.png" height="40" alt="Hetzner" />
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SPONSORS:END -->
|
||||
|
||||
<br />
|
||||
|
||||
## Support
|
||||
|
||||
Bugs and ideas for Termix itself (login, hosts, credentials, sharing, sync, the app and desktop app) go in this repo: [report a bug](https://github.com/Termix-SSH/Termix/issues/new?template=bug_report.yml) or [request a feature](https://github.com/Termix-SSH/Termix/issues/new?template=feature_request.yml).
|
||||
|
||||
Every plugin has its own repo, so a problem with the terminal, file manager, Docker, remote desktop or any other plugin goes in that plugin's repo (see the table above, or use Report an issue on the plugin's page in the app, which fills in your versions for you). Not sure where it goes? Open it here and it will be moved.
|
||||
|
||||
You need to be logged in to GitHub. Please be as detailed as possible, preferably in English.
|
||||
|
||||
For discussions and questions, join the [Discord](https://discord.gg/jVQGdvHDrf) server. Update videos are on [YouTube](https://www.youtube.com/@TermixSSH/videos).
|
||||
|
||||
<br />
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the Apache License Version 2.0. See [LICENSE](LICENSE) for more information.
|
||||
# License
|
||||
Distributed under the Apache License Version 2.0. See LICENSE for more information.
|
||||
+6
-10
@@ -1,25 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "radix-lyra",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "src/ui/index.css",
|
||||
"baseColor": "neutral",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "zinc",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"rtl": false,
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"menuColor": "default",
|
||||
"menuAccent": "subtle",
|
||||
"registries": {}
|
||||
}
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
+35
-96
@@ -1,20 +1,12 @@
|
||||
# Stage 1: Install dependencies
|
||||
# The builders only produce JS, so they run on the build machine's own arch
|
||||
# once instead of under QEMU per target. Rolldown hangs under arm64 emulation.
|
||||
FROM --platform=$BUILDPLATFORM node:24-slim AS deps
|
||||
# Stage 1: Install dependencies and build frontend
|
||||
FROM node:18-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
COPY package*.json ./
|
||||
COPY packages/plugin-sdk/package.json ./packages/plugin-sdk/package.json
|
||||
COPY .npmrc ./
|
||||
COPY vendor ./vendor
|
||||
|
||||
COPY scripts/patch-ssh2-agent.cjs ./scripts/
|
||||
|
||||
RUN npm ci --ignore-scripts && \
|
||||
node scripts/patch-ssh2-agent.cjs && \
|
||||
RUN npm ci --force && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 2: Build frontend
|
||||
@@ -23,12 +15,9 @@ WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN find public/fonts -name "*.ttf" ! -name "*Regular.ttf" ! -name "*Bold.ttf" ! -name "*Italic.ttf" -delete
|
||||
RUN npm run build
|
||||
|
||||
RUN npm cache clean --force && \
|
||||
NODE_OPTIONS="--max-old-space-size=3072" npm run build
|
||||
|
||||
# Stage 3: Build backend
|
||||
# Stage 3: Build backend TypeScript
|
||||
FROM deps AS backend-builder
|
||||
WORKDIR /app
|
||||
|
||||
@@ -36,104 +25,54 @@ COPY . .
|
||||
|
||||
RUN npm run build:backend
|
||||
|
||||
# Stage 4: Download OPKSSH binary for the target platform so the image works offline
|
||||
FROM node:24-slim AS opkssh-downloader
|
||||
ARG TARGETARCH
|
||||
ARG OPKSSH_VERSION=v0.16.0
|
||||
ARG OPKSSH_SHA256_AMD64=c018c3e7baf98612b923e742dd87be38650bf61e3b755fb2bc90de177568b1bf
|
||||
ARG OPKSSH_SHA256_ARM64=9dd10c2b6ce99cde18e52c054877ca014134b291fd82afe71741c68db4f83d44
|
||||
WORKDIR /opkssh
|
||||
|
||||
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN case "$TARGETARCH" in \
|
||||
amd64) OPKSSH_ARCH=amd64; OPKSSH_SHA256="$OPKSSH_SHA256_AMD64" ;; \
|
||||
arm64) OPKSSH_ARCH=arm64; OPKSSH_SHA256="$OPKSSH_SHA256_ARM64" ;; \
|
||||
*) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \
|
||||
esac && \
|
||||
curl -fSL -o "opkssh-linux-${OPKSSH_ARCH}" \
|
||||
"https://github.com/openpubkey/opkssh/releases/download/${OPKSSH_VERSION}/opkssh-linux-${OPKSSH_ARCH}" && \
|
||||
echo "$OPKSSH_SHA256 opkssh-linux-${OPKSSH_ARCH}" | sha256sum -c - && \
|
||||
chmod 755 "opkssh-linux-${OPKSSH_ARCH}" && \
|
||||
echo -n "$OPKSSH_VERSION" > version.txt
|
||||
|
||||
# Stage 5: Production dependencies only
|
||||
FROM node:24-slim AS production-deps
|
||||
# Stage 4: Production dependencies
|
||||
FROM node:18-alpine AS production-deps
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package*.json ./
|
||||
# The plugin SDK is a workspace package core imports at runtime, so npm ci
|
||||
# has to see it to link it and install its dependencies.
|
||||
COPY packages/plugin-sdk/package.json ./packages/plugin-sdk/package.json
|
||||
COPY .npmrc ./
|
||||
COPY vendor ./vendor
|
||||
|
||||
COPY scripts/patch-ssh2-agent.cjs ./scripts/
|
||||
|
||||
RUN npm ci --omit=dev --ignore-scripts && \
|
||||
node scripts/patch-ssh2-agent.cjs && \
|
||||
rm -rf node_modules/better-sqlite3/prebuilds && \
|
||||
npm run build-release --prefix node_modules/better-sqlite3 && \
|
||||
test -f node_modules/better-sqlite3/build/Release/better_sqlite3.node && \
|
||||
npm rebuild bcryptjs ssh2 && \
|
||||
RUN npm ci --only=production --ignore-scripts --force && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 6: Final optimized image
|
||||
FROM node:24-slim
|
||||
# Stage 5: Build native modules
|
||||
FROM node:18-alpine AS native-builder
|
||||
WORKDIR /app
|
||||
|
||||
# The release the opkssh-downloader stage baked in, so the plugin trusts that
|
||||
# binary when the build picks a version other than its pinned one.
|
||||
ARG OPKSSH_VERSION=v0.16.0
|
||||
ARG OPKSSH_SHA256_AMD64=c018c3e7baf98612b923e742dd87be38650bf61e3b755fb2bc90de177568b1bf
|
||||
ARG OPKSSH_SHA256_ARM64=9dd10c2b6ce99cde18e52c054877ca014134b291fd82afe71741c68db4f83d44
|
||||
RUN apk add --no-cache python3 make g++
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm ci --only=production bcryptjs better-sqlite3 --force && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 6: Final image
|
||||
FROM node:18-alpine
|
||||
ENV DATA_DIR=/app/data \
|
||||
OPKSSH_BUNDLED_DIR=/app/opkssh-bundled \
|
||||
OPKSSH_VERSION=$OPKSSH_VERSION \
|
||||
OPKSSH_SHA256_AMD64=$OPKSSH_SHA256_AMD64 \
|
||||
OPKSSH_SHA256_ARM64=$OPKSSH_SHA256_ARM64 \
|
||||
PORT=8080 \
|
||||
NODE_ENV=production
|
||||
|
||||
RUN apt-get update && apt-get install -y nginx gettext-base openssl ca-certificates gosu wget && \
|
||||
update-ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
mkdir -p /app/data /app/uploads /app/nginx /tmp/nginx && \
|
||||
chown -R node:node /app /tmp/nginx && \
|
||||
chmod 755 /app/data /app/uploads /app/nginx /tmp/nginx
|
||||
RUN apk add --no-cache nginx gettext su-exec && \
|
||||
mkdir -p /app/data && \
|
||||
chown -R node:node /app/data
|
||||
|
||||
COPY docker/nginx.conf /app/nginx/nginx.conf.template
|
||||
COPY docker/nginx-https.conf /app/nginx/nginx-https.conf.template
|
||||
COPY docker/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html
|
||||
|
||||
COPY --chown=node:node --from=frontend-builder /app/dist /app/html
|
||||
WORKDIR /app
|
||||
|
||||
COPY --chown=node:node --from=production-deps /app/node_modules /app/node_modules
|
||||
COPY --chown=node:node --from=backend-builder /app/dist/backend ./dist/backend
|
||||
# Plugins pinned in docker/bundled-plugins.json, resolved as dist/plugins by
|
||||
# getBundledPluginsDir().
|
||||
COPY --chown=node:node --from=backend-builder /app/dist/plugins ./dist/plugins
|
||||
# Target of node_modules/@termix-ssh/plugin-sdk, which core and the plugins import.
|
||||
COPY --chown=node:node --from=backend-builder /app/packages/plugin-sdk/package.json ./packages/plugin-sdk/package.json
|
||||
COPY --chown=node:node --from=backend-builder /app/packages/plugin-sdk/dist ./packages/plugin-sdk/dist
|
||||
# Pre-baked OPKSSH binary. The opkssh plugin uses it when its checksum
|
||||
# matches, so an offline install never downloads one.
|
||||
COPY --chown=node:node --from=opkssh-downloader /opkssh /app/opkssh-bundled
|
||||
COPY --chown=node:node package.json ./
|
||||
# Schema for Postgres and MySQL. Unused by the default SQLite deployment, which
|
||||
# builds its tables at startup instead.
|
||||
COPY --chown=node:node drizzle ./drizzle
|
||||
COPY --from=production-deps /app/node_modules /app/node_modules
|
||||
COPY --from=native-builder /app/node_modules/bcryptjs /app/node_modules/bcryptjs
|
||||
COPY --from=native-builder /app/node_modules/better-sqlite3 /app/node_modules/better-sqlite3
|
||||
COPY --from=backend-builder /app/dist/backend ./dist/backend
|
||||
|
||||
COPY package.json ./
|
||||
RUN chown -R node:node /app
|
||||
|
||||
VOLUME ["/app/data"]
|
||||
|
||||
EXPOSE ${PORT}
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD wget -q -O /dev/null http://localhost:30001/health || exit 1
|
||||
EXPOSE ${PORT} 8081 8082 8083 8084
|
||||
|
||||
COPY docker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
CMD ["/entrypoint.sh"]
|
||||
CMD ["/entrypoint.sh"]
|
||||
@@ -1,265 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"id": "acme-ssl",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-ACME-SSL/releases/download/v1.0.0/acme-ssl-1.0.0.tmxplug",
|
||||
"sha256": "34aa172b2f6bc6a773ebdff2ec0f590d411ce258fd43176bdddb4c30d1fe30da"
|
||||
},
|
||||
{
|
||||
"id": "ai",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-AI/releases/download/v1.0.0/ai-1.0.0.tmxplug",
|
||||
"sha256": "ad291a2c6f6f01b72ebd275e8d202b78f55bc13a1e1a40f419d04e71b2fbd06b"
|
||||
},
|
||||
{
|
||||
"id": "alerts",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Alerts/releases/download/v1.0.0/alerts-1.0.0.tmxplug",
|
||||
"sha256": "3fe008f9d2a32e2b7111399054a2264ea5cf5d71264cc31e85cdab3e909cc62f",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "automations",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Automations/releases/download/v1.0.0/automations-1.0.0.tmxplug",
|
||||
"sha256": "76d4cff6e78d40ec67e899f0c7b2aca43d35a47b9a15071d0a8f5a8d939af9a9"
|
||||
},
|
||||
{
|
||||
"id": "docker",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Docker/releases/download/v1.0.0/docker-1.0.0.tmxplug",
|
||||
"sha256": "641e564ba915a72efed4236272d63f6fff43904309833870f3554d3e9bd28dfa",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "file-manager",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-File-Manager/releases/download/v1.0.0/file-manager-1.0.0.tmxplug",
|
||||
"sha256": "1cafccfe86a29e2f318026ca7bc20629df94331c81209607976dafd7feac0ca4",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fleets",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Fleets/releases/download/v1.0.0/fleets-1.0.0.tmxplug",
|
||||
"sha256": "1ebeccd6b2a8e9510ab56658374d0b87f652149101d14956752a696ca920f611"
|
||||
},
|
||||
{
|
||||
"id": "homepage",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Homepage/releases/download/v1.0.0/homepage-1.0.0.tmxplug",
|
||||
"sha256": "65cd21802f6a71f3b3c582bc0007bfc91160abc161b2390bce715fd2ed987f99"
|
||||
},
|
||||
{
|
||||
"id": "host-metrics",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Host-Metrics/releases/download/v1.0.0/host-metrics-1.0.0.tmxplug",
|
||||
"sha256": "1afce5489038e5e30b55210e8e43ba93e0446fe087e2952af75a402dbf809ea9",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ldap",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-LDAP/releases/download/v1.0.0/ldap-1.0.0.tmxplug",
|
||||
"sha256": "1df08a931457043ba500689a73b4b5ab2bfb43630f377557e0fb13280b996334"
|
||||
},
|
||||
{
|
||||
"id": "network-topology",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Network-Topology/releases/download/v1.0.0/network-topology-1.0.0.tmxplug",
|
||||
"sha256": "dc3ad943c1753b352b4d80c09836a293a8767293061ddf2e641575bae97124e9"
|
||||
},
|
||||
{
|
||||
"id": "opkssh",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-OPKSSH/releases/download/v1.0.0/opkssh-1.0.0.tmxplug",
|
||||
"sha256": "91cc1575aa1ff84632e0b6a4da68df3a7df4b8e18431b9c0378d314b886ed55d"
|
||||
},
|
||||
{
|
||||
"id": "proxmox",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Proxmox/releases/download/v1.0.0/proxmox-1.0.0.tmxplug",
|
||||
"sha256": "09891a3ab67a5b6589d8ab9e0fc88d8c63ff9d4e52ed8e7cbd0801a5e64e593f"
|
||||
},
|
||||
{
|
||||
"id": "remote-desktop",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Remote-Desktop/releases/download/v1.0.0/remote-desktop-1.0.0.tmxplug",
|
||||
"sha256": "7b24691953550458ee1609372443eeb5580d20091b02c95011c0427268350efc",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "secret-sources",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Secret-Sources/releases/download/v1.0.0/secret-sources-1.0.0.tmxplug",
|
||||
"sha256": "04e9cfca70ffafc41546ddf0f1f6411743a2e0e9835b26ad5c0b91ac11028485"
|
||||
},
|
||||
{
|
||||
"id": "serial",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Serial/releases/download/v1.0.0/serial-1.0.0.tmxplug",
|
||||
"sha256": "2470acbd6c4c343c3d89dada972051f1ee7aace88af1e6719b92f19a4a6e46ea",
|
||||
"onboarding": {
|
||||
"recommended": "desktop",
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "session-recording",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Session-Recording/releases/download/v1.0.0/session-recording-1.0.0.tmxplug",
|
||||
"sha256": "6b630ca0e08d79be7cb49366c898586ee3416a518f8e200157a6191c2c7c9ab7"
|
||||
},
|
||||
{
|
||||
"id": "session-sharing",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Session-Sharing/releases/download/v1.0.0/session-sharing-1.0.0.tmxplug",
|
||||
"sha256": "0c0d3f2d63184d4a4b2a90b11a1ee247ddc937abba76af74eb39e27048b412f9"
|
||||
},
|
||||
{
|
||||
"id": "snippets",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Snippets/releases/download/v1.0.0/snippets-1.0.0.tmxplug",
|
||||
"sha256": "47872d08cdf4a15b50c8f90ca125276a92579147a27cb6b5639a84a01160abe5",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ssh-terminal",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-SSH-Terminal/releases/download/v1.0.0/ssh-terminal-1.0.0.tmxplug",
|
||||
"sha256": "5b5a357bbf9a503c6b68725245712a99fa8ea0eec0baff64319be28950acac79",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sso",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-SSO/releases/download/v1.0.1/sso-1.0.1.tmxplug",
|
||||
"sha256": "ba7485ba058c784975609f6960bbaf7ec2018bcdce40b47308efc92ca96fdab5",
|
||||
"onboarding": {
|
||||
"recommended": false,
|
||||
"consent": false,
|
||||
"enabledByEnv": ["OIDC_CLIENT_ID"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "step-ca",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Step-CA/releases/download/v1.0.0/step-ca-1.0.0.tmxplug",
|
||||
"sha256": "05209afbaeb104ff77fecb5cf26a7823b9ed66031eac7557d3216fc3b861f7a6"
|
||||
},
|
||||
{
|
||||
"id": "tailscale",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Tailscale/releases/download/v1.0.0/tailscale-1.0.0.tmxplug",
|
||||
"sha256": "e9840bddef696b24354b9f04f2c97e164c3879f3fd1b337347de728db522874e"
|
||||
},
|
||||
{
|
||||
"id": "telemetry",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Telemetry/releases/download/v1.0.0/telemetry-1.0.0.tmxplug",
|
||||
"sha256": "b41210d638b93470891ab238e3d1180a0e0d0f0c697b1c2079156416dec05966",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "termix-identity",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Termix-Identity/releases/download/v1.0.0/termix-identity-1.0.0.tmxplug",
|
||||
"sha256": "facd9f1c6036202e7c6b1020408ce49c7ba4bc687a8f8b93ccf60e97f473f897"
|
||||
},
|
||||
{
|
||||
"id": "tmux-monitor",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Tmux-Monitor/releases/download/v1.0.0/tmux-monitor-1.0.0.tmxplug",
|
||||
"sha256": "d453e0c5f1bf54160615d5df4e12eac0d97fea3c78c0aad5ebe8552e1f2de42c"
|
||||
},
|
||||
{
|
||||
"id": "totp",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-TOTP/releases/download/v1.0.0/totp-1.0.0.tmxplug",
|
||||
"sha256": "a2d389048d16e31c089cf211fe2fb37fcfb33369497b58ee445e8626e9ec494d",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tunnels",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Tunnels/releases/download/v1.0.0/tunnels-1.0.0.tmxplug",
|
||||
"sha256": "dc6c2942490c07ec1f9a4065850288cbb00c42dae64397937d2551d689314939",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "vault",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Vault/releases/download/v1.0.0/vault-1.0.0.tmxplug",
|
||||
"sha256": "bdad88ed576ed30b464c9cbddab4d9bb60696581dc1b815b76e1b4a08500f870"
|
||||
},
|
||||
{
|
||||
"id": "wake-on-lan",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Wake-On-LAN/releases/download/v1.0.0/wake-on-lan-1.0.0.tmxplug",
|
||||
"sha256": "3e7d4c8a9a20cde95d8594d4ae8e1fa0469d0751be9f00249f6431b10ada9ea9"
|
||||
},
|
||||
{
|
||||
"id": "warpgate",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Warpgate/releases/download/v1.0.0/warpgate-1.0.0.tmxplug",
|
||||
"sha256": "18ed1c8238ecf57b5776ad93c6533d7040b988ae765012c5da591b85faa02d2e"
|
||||
},
|
||||
{
|
||||
"id": "web-endpoint",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Web-Endpoint/releases/download/v1.0.0/web-endpoint-1.0.0.tmxplug",
|
||||
"sha256": "7f69e608eccd8cc6fa2436bffb3e2c3c8aae6cebebf7341913f15e7f9be58e42"
|
||||
},
|
||||
{
|
||||
"id": "webauthn",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-WebAuthn/releases/download/v1.0.0/webauthn-1.0.0.tmxplug",
|
||||
"sha256": "dafcd7bfffc39b60a14333164dfd8ca70986da1390285359669d0293cd050121",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "workspaces",
|
||||
"source": "tmxplug",
|
||||
"url": "https://github.com/Termix-SSH/Plugin-Workspaces/releases/download/v1.0.0/workspaces-1.0.0.tmxplug",
|
||||
"sha256": "1ee3a07bd8d61b46b6fbe118d2a424f8027575282287622b467e83a4356e6412",
|
||||
"onboarding": {
|
||||
"recommended": true,
|
||||
"consent": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
services:
|
||||
termix-dev:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: termix-dev
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8081:8080"
|
||||
volumes:
|
||||
- termix-dev-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
NODE_ENV: development
|
||||
GUACD_HOST: "guacd-dev"
|
||||
GUACD_TUNNEL_HOST: "termix-dev"
|
||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||
GUACD_DRIVE_PATH: "/termix-data/rdp-drive"
|
||||
# REDIS_URL: "redis://redis:6379"
|
||||
# TERMIX_REDIS_PREFIX: "termix:collab"
|
||||
# TERMIX_STEP_CA_REDIS_PREFIX: "termix:step-ca"
|
||||
depends_on:
|
||||
- guacd-dev
|
||||
networks:
|
||||
- termix-dev-net
|
||||
|
||||
guacd-dev:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd-dev
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- termix-dev-data:/termix-data
|
||||
networks:
|
||||
- termix-dev-net
|
||||
|
||||
volumes:
|
||||
termix-dev-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-dev-net:
|
||||
driver: bridge
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
termix:
|
||||
image: ghcr.io/termix-ssh/termix:latest
|
||||
image: ghcr.io/lukegus/termix:latest
|
||||
container_name: termix
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -9,47 +9,7 @@ services:
|
||||
- termix-data:/app/data
|
||||
environment:
|
||||
PORT: "8080"
|
||||
GUACD_HOST: "guacd"
|
||||
GUACD_TUNNEL_HOST: "termix"
|
||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||
# Where guacd stores files for RDP drive redirection (one folder per
|
||||
# user is created underneath). Must be writable by guacd's user.
|
||||
GUACD_DRIVE_PATH: "/termix-data/rdp-drive"
|
||||
# Multi-instance deployments should point every backend at the same
|
||||
# Redis. Without it, collaboration rooms keep their single-instance
|
||||
# in-memory fallback.
|
||||
# REDIS_URL: "redis://redis:6379"
|
||||
# TERMIX_REDIS_PREFIX: "termix:collab"
|
||||
# TERMIX_STEP_CA_REDIS_PREFIX: "termix:step-ca"
|
||||
# Hardened deployments can require keys from environment variables or
|
||||
# Docker secrets mounted through JWT_SECRET_FILE, DATABASE_KEY_FILE,
|
||||
# ENCRYPTION_KEY_FILE and INTERNAL_AUTH_TOKEN_FILE.
|
||||
# TERMIX_REQUIRE_EXTERNAL_SECRETS: "true"
|
||||
# Trusted reverse-proxy authentication is disabled by default. When
|
||||
# enabled, do not expose this container directly to untrusted clients.
|
||||
# TRUSTED_PROXY_AUTH_ENABLED: "true"
|
||||
# TRUSTED_PROXY_AUTH_TRUSTED_PROXIES: "172.16.0.0/12"
|
||||
# TRUSTED_PROXY_AUTH_ROLE_MAP: '{"operators":["user"]}'
|
||||
# TRUSTED_PROXY_AUTH_USERNAME_HEADER: "x-forwarded-username"
|
||||
# TRUSTED_PROXY_AUTH_ROLE_HEADER: "x-forwarded-role"
|
||||
depends_on:
|
||||
- guacd
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
guacd:
|
||||
image: guacamole/guacd:1.6.0
|
||||
container_name: guacd
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- termix-data:/termix-data
|
||||
networks:
|
||||
- termix-net
|
||||
|
||||
volumes:
|
||||
termix-data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
termix-net:
|
||||
driver: bridge
|
||||
driver: local
|
||||
+12
-200
@@ -1,217 +1,29 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
PUID=${PUID:-1000}
|
||||
PGID=${PGID:-1000}
|
||||
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
if [ "$PUID" = "0" ]; then
|
||||
echo "Running as root (PUID=0, PGID=$PGID)"
|
||||
chown -R root:root /app/data /app/uploads /tmp/nginx 2>/dev/null || true
|
||||
else
|
||||
echo "Setting up user permissions (PUID: $PUID, PGID: $PGID)..."
|
||||
|
||||
groupmod -o -g "$PGID" node 2>/dev/null || true
|
||||
usermod -o -u "$PUID" node 2>/dev/null || true
|
||||
|
||||
chown -R node:node /app/data /app/uploads /app/html /tmp/nginx 2>/dev/null || true
|
||||
|
||||
echo "User node is now UID: $PUID, GID: $PGID"
|
||||
|
||||
exec gosu node:node "$0" "$@"
|
||||
fi
|
||||
fi
|
||||
|
||||
DATA_DIR=${DATA_DIR:-/app/data}
|
||||
|
||||
RUNTIME_ENABLE_SSL_SET=${ENABLE_SSL+x}
|
||||
RUNTIME_ENABLE_SSL=${ENABLE_SSL-}
|
||||
RUNTIME_SSL_PORT_SET=${SSL_PORT+x}
|
||||
RUNTIME_SSL_PORT=${SSL_PORT-}
|
||||
RUNTIME_SSL_CERT_PATH_SET=${SSL_CERT_PATH+x}
|
||||
RUNTIME_SSL_CERT_PATH=${SSL_CERT_PATH-}
|
||||
RUNTIME_SSL_KEY_PATH_SET=${SSL_KEY_PATH+x}
|
||||
RUNTIME_SSL_KEY_PATH=${SSL_KEY_PATH-}
|
||||
RUNTIME_SSL_DOMAIN_SET=${SSL_DOMAIN+x}
|
||||
RUNTIME_SSL_DOMAIN=${SSL_DOMAIN-}
|
||||
|
||||
if [ -f "$DATA_DIR/.env" ]; then
|
||||
echo "Loading persisted SSL settings from $DATA_DIR/.env"
|
||||
set -a
|
||||
. "$DATA_DIR/.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
[ "$RUNTIME_ENABLE_SSL_SET" = "x" ] && ENABLE_SSL=$RUNTIME_ENABLE_SSL
|
||||
[ "$RUNTIME_SSL_PORT_SET" = "x" ] && SSL_PORT=$RUNTIME_SSL_PORT
|
||||
[ "$RUNTIME_SSL_CERT_PATH_SET" = "x" ] && SSL_CERT_PATH=$RUNTIME_SSL_CERT_PATH
|
||||
[ "$RUNTIME_SSL_KEY_PATH_SET" = "x" ] && SSL_KEY_PATH=$RUNTIME_SSL_KEY_PATH
|
||||
[ "$RUNTIME_SSL_DOMAIN_SET" = "x" ] && SSL_DOMAIN=$RUNTIME_SSL_DOMAIN
|
||||
|
||||
export PORT=${PORT:-8080}
|
||||
export ENABLE_SSL=${ENABLE_SSL:-false}
|
||||
export SSL_PORT=${SSL_PORT:-8443}
|
||||
export SSL_CERT_PATH=${SSL_CERT_PATH:-/app/data/ssl/termix.crt}
|
||||
export SSL_KEY_PATH=${SSL_KEY_PATH:-/app/data/ssl/termix.key}
|
||||
export TERMIX_SSL_TERMINATED_BY_NGINX=true
|
||||
|
||||
echo "Configuring web UI to run on port: $PORT"
|
||||
|
||||
if [ "$ENABLE_SSL" = "true" ]; then
|
||||
echo "SSL enabled - using HTTPS configuration with redirect"
|
||||
NGINX_CONF_SOURCE="/app/nginx/nginx-https.conf.template"
|
||||
else
|
||||
echo "SSL disabled - using HTTP-only configuration (default)"
|
||||
NGINX_CONF_SOURCE="/app/nginx/nginx.conf.template"
|
||||
fi
|
||||
envsubst '${PORT}' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf.tmp
|
||||
mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf
|
||||
|
||||
mkdir -p /tmp/nginx
|
||||
envsubst '${PORT} ${SSL_PORT} ${SSL_CERT_PATH} ${SSL_KEY_PATH}' < $NGINX_CONF_SOURCE > /tmp/nginx/nginx.conf
|
||||
|
||||
# Which proxies may set the client IP through X-Forwarded-For. Unset keeps
|
||||
# the private ranges in the template.
|
||||
if [ -n "$TRUSTED_PROXIES" ]; then
|
||||
REAL_IP_LINES=""
|
||||
for proxy in $(echo "$TRUSTED_PROXIES" | tr ',' ' '); do
|
||||
case "$proxy" in
|
||||
*[!0-9a-fA-F:./]*) echo "Ignoring invalid TRUSTED_PROXIES entry: $proxy" ;;
|
||||
*) REAL_IP_LINES="${REAL_IP_LINES} set_real_ip_from ${proxy};\n" ;;
|
||||
esac
|
||||
done
|
||||
echo "Trusting X-Forwarded-For from: $TRUSTED_PROXIES"
|
||||
awk -v lines="$REAL_IP_LINES" '
|
||||
/# BEGIN TRUSTED_PROXIES/ { printf "%s", lines; skip = 1; next }
|
||||
/# END TRUSTED_PROXIES/ { skip = 0; next }
|
||||
!skip
|
||||
' /tmp/nginx/nginx.conf > /tmp/nginx/nginx.conf.tmp
|
||||
mv /tmp/nginx/nginx.conf.tmp /tmp/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_SSL" = "true" ] && [ "$PORT" = "$SSL_PORT" ]; then
|
||||
echo "HTTP and HTTPS use port $SSL_PORT; disabling the HTTP redirect listener"
|
||||
sed -i '/# BEGIN HTTP_REDIRECT_SERVER/,/# END HTTP_REDIRECT_SERVER/d' /tmp/nginx/nginx.conf
|
||||
fi
|
||||
|
||||
mkdir -p /app/data /app/uploads
|
||||
chmod 755 /app/data /app/uploads 2>/dev/null || true
|
||||
|
||||
if [ -w /app/data ]; then
|
||||
echo "Data directory is writable"
|
||||
else
|
||||
echo "WARNING: Data directory is not writable. Plugins that keep files (OPKSSH, recordings) may fail."
|
||||
ls -ld /app/data
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_SSL" = "true" ]; then
|
||||
echo "Checking SSL certificate configuration..."
|
||||
mkdir -p /app/data/ssl
|
||||
chmod 755 /app/data/ssl 2>/dev/null || true
|
||||
|
||||
DOMAIN=${SSL_DOMAIN:-localhost}
|
||||
|
||||
if [ -f "/app/data/ssl/termix.crt" ] && [ -f "/app/data/ssl/termix.key" ]; then
|
||||
echo "SSL certificates found, checking validity..."
|
||||
|
||||
if openssl x509 -in /app/data/ssl/termix.crt -checkend 2592000 -noout >/dev/null 2>&1; then
|
||||
echo "SSL certificates are valid and will be reused for domain: $DOMAIN"
|
||||
else
|
||||
SUBJECT=$(openssl x509 -in /app/data/ssl/termix.crt -noout -subject 2>/dev/null | sed 's/^subject=//')
|
||||
ISSUER=$(openssl x509 -in /app/data/ssl/termix.crt -noout -issuer 2>/dev/null | sed 's/^issuer=//')
|
||||
# Only replace our own self-signed certificate. A CA-issued one is
|
||||
# kept until it expires, even when nothing renews it.
|
||||
if [ -n "$SUBJECT" ] && [ "$SUBJECT" = "$ISSUER" ]; then
|
||||
echo "Self-signed SSL certificate is expired or expiring soon, regenerating..."
|
||||
rm -f /app/data/ssl/termix.crt /app/data/ssl/termix.key
|
||||
else
|
||||
echo "WARNING: SSL certificate expires within 30 days and was not issued by Termix. Renew it."
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "SSL certificates not found, will generate new ones..."
|
||||
fi
|
||||
|
||||
if [ ! -f "/app/data/ssl/termix.crt" ] || [ ! -f "/app/data/ssl/termix.key" ]; then
|
||||
echo "Generating SSL certificates for domain: $DOMAIN"
|
||||
|
||||
cat > /app/data/ssl/openssl.conf << EOF
|
||||
[req]
|
||||
default_bits = 2048
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
distinguished_name = dn
|
||||
req_extensions = v3_req
|
||||
|
||||
[dn]
|
||||
C=US
|
||||
ST=State
|
||||
L=City
|
||||
O=Termix
|
||||
OU=IT Department
|
||||
CN=$DOMAIN
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = $DOMAIN
|
||||
DNS.2 = localhost
|
||||
DNS.3 = 127.0.0.1
|
||||
IP.1 = 127.0.0.1
|
||||
IP.2 = ::1
|
||||
IP.3 = 0.0.0.0
|
||||
EOF
|
||||
|
||||
openssl genrsa -out /app/data/ssl/termix.key 2048
|
||||
|
||||
openssl req -new -x509 -key /app/data/ssl/termix.key -out /app/data/ssl/termix.crt -days 365 -config /app/data/ssl/openssl.conf -extensions v3_req
|
||||
|
||||
chmod 600 /app/data/ssl/termix.key
|
||||
chmod 644 /app/data/ssl/termix.crt
|
||||
|
||||
rm -f /app/data/ssl/openssl.conf
|
||||
|
||||
echo "SSL certificates generated successfully for domain: $DOMAIN"
|
||||
fi
|
||||
fi
|
||||
mkdir -p /app/data
|
||||
chown -R node:node /app/data
|
||||
chmod 755 /app/data
|
||||
|
||||
echo "Starting nginx..."
|
||||
nginx -c /tmp/nginx/nginx.conf
|
||||
|
||||
# Inject runtime BASE_PATH into frontend if configured
|
||||
if [ -n "$BASE_PATH" ]; then
|
||||
echo "Injecting BASE_PATH: $BASE_PATH"
|
||||
# Strip trailing slash for use as a path prefix
|
||||
CLEAN_BASE_PATH="${BASE_PATH%/}"
|
||||
case "$CLEAN_BASE_PATH" in
|
||||
/*) ;;
|
||||
*) echo "BASE_PATH must start with /" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$CLEAN_BASE_PATH" in
|
||||
*[!A-Za-z0-9_./~-]*) echo "BASE_PATH contains unsupported characters" >&2; exit 1 ;;
|
||||
esac
|
||||
find /app/html -name "index.html" -exec sed -i "s|name=\"termix-base-path\" content=\"\"|name=\"termix-base-path\" content=\"$CLEAN_BASE_PATH\"|g" {} \;
|
||||
# Patch sw.js static asset paths with the base path prefix
|
||||
find /app/html -name "sw.js" -exec sed -i "s|__TERMIX_SW_BASE_PATH__|$CLEAN_BASE_PATH|g" {} \;
|
||||
else
|
||||
# No base path - replace placeholder with empty string so paths stay absolute from root
|
||||
find /app/html -name "sw.js" -exec sed -i "s|__TERMIX_SW_BASE_PATH__||g" {} \;
|
||||
fi
|
||||
nginx
|
||||
|
||||
echo "Starting backend services..."
|
||||
cd /app
|
||||
export NODE_ENV=production
|
||||
|
||||
if [ -f "package.json" ]; then
|
||||
VERSION=$(grep '"version"' package.json | sed 's/.*"version": *"\([^"]*\)".*/\1/')
|
||||
if [ -n "$VERSION" ]; then
|
||||
export VERSION
|
||||
else
|
||||
echo "Warning: Could not extract version from package.json"
|
||||
fi
|
||||
if command -v su-exec > /dev/null 2>&1; then
|
||||
su-exec node node dist/backend/starter.js
|
||||
else
|
||||
echo "Warning: package.json not found"
|
||||
su -s /bin/sh node -c "node dist/backend/starter.js"
|
||||
fi
|
||||
|
||||
exec node dist/backend/backend/starter.js
|
||||
echo "All services started"
|
||||
|
||||
tail -f /dev/null
|
||||
@@ -1,471 +0,0 @@
|
||||
worker_processes 1;
|
||||
master_process off;
|
||||
pid /tmp/nginx/nginx.pid;
|
||||
error_log /tmp/nginx/error.log warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
access_log /tmp/nginx/access.log;
|
||||
|
||||
client_body_temp_path /tmp/nginx/client_body;
|
||||
proxy_temp_path /tmp/nginx/proxy_temp;
|
||||
fastcgi_temp_path /tmp/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/nginx/uwsgi_temp;
|
||||
scgi_temp_path /tmp/nginx/scgi_temp;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Static assets only. API responses arrive already gzipped from the node
|
||||
# backend, and gzip_proxied would otherwise have nginx decompress and
|
||||
# recompress them for nothing.
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 2048;
|
||||
gzip_comp_level 5;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/wasm
|
||||
image/svg+xml;
|
||||
client_header_timeout 300s;
|
||||
|
||||
# BEGIN TRUSTED_PROXIES
|
||||
set_real_ip_from 127.0.0.1;
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
# END TRUSTED_PROXIES
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
|
||||
default $http_x_forwarded_proto;
|
||||
'' $scheme;
|
||||
}
|
||||
|
||||
map $http_x_forwarded_host $proxy_x_forwarded_host {
|
||||
default $http_x_forwarded_host;
|
||||
'' $http_host;
|
||||
}
|
||||
|
||||
map $http_x_forwarded_port $proxy_x_forwarded_port {
|
||||
default $http_x_forwarded_port;
|
||||
'' '';
|
||||
}
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# BEGIN HTTP_REDIRECT_SERVER
|
||||
server {
|
||||
listen ${PORT};
|
||||
server_name _;
|
||||
|
||||
# ACME http-01 checks arrive on plain HTTP and must not be redirected.
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host:${SSL_PORT}$request_uri;
|
||||
}
|
||||
}
|
||||
# END HTTP_REDIRECT_SERVER
|
||||
|
||||
server {
|
||||
listen ${SSL_PORT} ssl;
|
||||
server_name _;
|
||||
client_max_body_size 50m;
|
||||
|
||||
absolute_redirect off;
|
||||
|
||||
ssl_certificate ${SSL_CERT_PATH};
|
||||
ssl_certificate_key ${SSL_KEY_PATH};
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location = /sw.js {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /manifest.json {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /assets/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /fonts/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /icons/ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* ^/[^/]+\.(js|css|png|jpe?g|gif|ico|svg|webp|woff2?|ttf|eot)$ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.map$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
return 404;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /app/html;
|
||||
index index.html index.htm;
|
||||
expires off;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval' 'sha256-0FPou4vGHwupDie6Xais6VntpJ4yaK9E6TyhXLwZe8o='; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: http: https:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; media-src 'self' data: blob: http: https:; worker-src 'self' blob:; frame-src http: https:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location ~ ^/users/sessions(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/users(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
}
|
||||
|
||||
location ~ ^/version(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/releases(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/rbac(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credentials(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
location ~ ^/ssh-auth(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/sync(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/audit-logs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/plugins(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
# Plugin frontend bundles, stylesheets and locales. Public like
|
||||
# /assets; the backend picks the cache policy from the ?v= query.
|
||||
location ^~ /plugin-assets/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
# Every plugin's HTTP routes. One block, no per-plugin entries: a
|
||||
# plugin serves at /plugin-api/<id>/ on the main backend and never
|
||||
# gets a port or a block of its own. Buffering is off so SSE streams
|
||||
# (AI, Proxmox discovery) reach the browser as they are produced, and
|
||||
# request buffering is off so large uploads stream through.
|
||||
location ^~ /plugin-api/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
|
||||
client_max_body_size 0;
|
||||
}
|
||||
|
||||
# Every plugin's WebSockets: terminal, Guacamole display, Docker
|
||||
# console. Served at /plugin-ws/<id>/<path> from the same backend.
|
||||
location ^~ /plugin-ws/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
||||
}
|
||||
|
||||
location ~ ^/open-tabs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/user-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credential-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/ui-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/database(/.*)?$ {
|
||||
client_max_body_size 5G;
|
||||
client_body_timeout 300s;
|
||||
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ ^/encryption(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/quick-connect {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
# File manager routes (recent/pinned/shortcuts, SFTP, transfers) moved
|
||||
# to the file-manager plugin, served under /plugin-api/file-manager/.
|
||||
# Session logs moved to the session-recording plugin, served under
|
||||
# /plugin-api/session-recording/.
|
||||
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
# Service links and the homepage widget canvas moved to the homepage
|
||||
# plugin, served under /plugin-api/homepage/.
|
||||
|
||||
location /dashboard/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /app/html;
|
||||
internal;
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-387
@@ -1,440 +1,84 @@
|
||||
worker_processes 1;
|
||||
master_process off;
|
||||
pid /tmp/nginx/nginx.pid;
|
||||
error_log /tmp/nginx/error.log warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
access_log /tmp/nginx/access.log;
|
||||
|
||||
client_body_temp_path /tmp/nginx/client_body;
|
||||
proxy_temp_path /tmp/nginx/proxy_temp;
|
||||
fastcgi_temp_path /tmp/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/nginx/uwsgi_temp;
|
||||
scgi_temp_path /tmp/nginx/scgi_temp;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Static assets only. API responses arrive already gzipped from the node
|
||||
# backend, and gzip_proxied would otherwise have nginx decompress and
|
||||
# recompress them for nothing.
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 2048;
|
||||
gzip_comp_level 5;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/wasm
|
||||
image/svg+xml;
|
||||
client_header_timeout 300s;
|
||||
|
||||
# BEGIN TRUSTED_PROXIES
|
||||
set_real_ip_from 127.0.0.1;
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
# END TRUSTED_PROXIES
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
|
||||
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
|
||||
default $http_x_forwarded_proto;
|
||||
'' $scheme;
|
||||
}
|
||||
|
||||
map $http_x_forwarded_host $proxy_x_forwarded_host {
|
||||
default $http_x_forwarded_host;
|
||||
'' $http_host;
|
||||
}
|
||||
|
||||
map $http_x_forwarded_port $proxy_x_forwarded_port {
|
||||
default $http_x_forwarded_port;
|
||||
'' '';
|
||||
}
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
server {
|
||||
listen ${PORT};
|
||||
server_name _;
|
||||
client_max_body_size 50m;
|
||||
|
||||
absolute_redirect off;
|
||||
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
location = /sw.js {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location = /manifest.json {
|
||||
root /app/html;
|
||||
expires off;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /assets/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /fonts/ {
|
||||
root /app/html;
|
||||
expires 1y;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ^~ /icons/ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* ^/[^/]+\.(js|css|png|jpe?g|gif|ico|svg|webp|woff2?|ttf|eot)$ {
|
||||
root /app/html;
|
||||
expires 30d;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.map$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
return 404;
|
||||
}
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /app/html;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
expires off;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval' 'sha256-0FPou4vGHwupDie6Xais6VntpJ4yaK9E6TyhXLwZe8o='; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: http: https:; font-src 'self' data:; connect-src 'self' http: https: ws: wss:; media-src 'self' data: blob: http: https:; worker-src 'self' blob:; frame-src http: https:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
|
||||
add_header X-Frame-Options "DENY" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location ~ ^/users/sessions(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
location /users/ {
|
||||
proxy_pass http://127.0.0.1:8081;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ ^/users(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
location /ssh/db/ {
|
||||
proxy_pass http://127.0.0.1:8081;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location ~ ^/version(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/releases(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/rbac(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credentials(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
|
||||
location ~ ^/ssh-auth(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/sync(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/audit-logs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/plugins(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
# Plugin frontend bundles, stylesheets and locales. Public like
|
||||
# /assets; the backend picks the cache policy from the ?v= query.
|
||||
location ^~ /plugin-assets/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
# Every plugin's HTTP routes. One block, no per-plugin entries: a
|
||||
# plugin serves at /plugin-api/<id>/ on the main backend and never
|
||||
# gets a port or a block of its own. Buffering is off so SSE streams
|
||||
# (AI, Proxmox discovery) reach the browser as they are produced, and
|
||||
# request buffering is off so large uploads stream through.
|
||||
location ^~ /plugin-api/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
|
||||
client_max_body_size 0;
|
||||
}
|
||||
|
||||
# Every plugin's WebSockets: terminal, Guacamole display, Docker
|
||||
# console. Served at /plugin-ws/<id>/<path> from the same backend.
|
||||
location ^~ /plugin-ws/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
|
||||
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
proxy_connect_timeout 10s;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
||||
}
|
||||
|
||||
location ~ ^/open-tabs(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/user-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/host-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/credential-sidebar(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/ui-preferences(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location ~ ^/database(/.*)?$ {
|
||||
client_max_body_size 5G;
|
||||
client_body_timeout 300s;
|
||||
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location ~ ^/encryption(/.*)?$ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
}
|
||||
|
||||
location /host/quick-connect {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
location /ssh/websocket/ {
|
||||
proxy_pass http://127.0.0.1:8082/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /host/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
location /ssh/tunnel/ {
|
||||
proxy_pass http://127.0.0.1:8083;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# File manager routes (recent/pinned/shortcuts, SFTP, transfers) moved
|
||||
# to the file-manager plugin, served under /plugin-api/file-manager/.
|
||||
# Session logs moved to the session-recording plugin, served under
|
||||
# /plugin-api/session-recording/.
|
||||
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
location /ssh/config_editor/ {
|
||||
proxy_pass http://127.0.0.1:8084;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Service links and the homepage widget canvas moved to the homepage
|
||||
# plugin, served under /plugin-api/homepage/.
|
||||
|
||||
location /dashboard/ {
|
||||
proxy_pass http://127.0.0.1:30001;
|
||||
location ~ ^/ssh/config_editor/(recent|pinned|shortcuts) {
|
||||
proxy_pass http://127.0.0.1:8081;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /app/html;
|
||||
internal;
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "mysql",
|
||||
schema: "./src/backend/database/db/schema.mysql.ts",
|
||||
out: "./drizzle/mysql",
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "postgresql",
|
||||
schema: "./src/backend/database/db/schema.pg.ts",
|
||||
out: "./drizzle/postgres",
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
dialect: "sqlite",
|
||||
schema: "./src/backend/database/db/schema.ts",
|
||||
out: "./drizzle/sqlite",
|
||||
});
|
||||
@@ -1,890 +0,0 @@
|
||||
CREATE TABLE `alert_firings` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`rule_id` int NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`host_name` text NOT NULL,
|
||||
`fired_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`resolved_at` text,
|
||||
`value` double,
|
||||
`message` text NOT NULL,
|
||||
`severity` text NOT NULL DEFAULT ('warning'),
|
||||
`acknowledged` boolean NOT NULL DEFAULT false,
|
||||
CONSTRAINT `alert_firings_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `alert_rule_channels` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`rule_id` int NOT NULL,
|
||||
`channel_id` int NOT NULL,
|
||||
CONSTRAINT `alert_rule_channels_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `alert_rules` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`trigger_type` text NOT NULL,
|
||||
`threshold_value` double,
|
||||
`threshold_duration_seconds` int,
|
||||
`cooldown_minutes` int NOT NULL DEFAULT 15,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `alert_rules_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `api_keys` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`token_hash` text NOT NULL,
|
||||
`token_prefix` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text,
|
||||
`last_used_at` text,
|
||||
`is_active` boolean NOT NULL DEFAULT true,
|
||||
CONSTRAINT `api_keys_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `audit_logs` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`username` text NOT NULL,
|
||||
`action` text NOT NULL,
|
||||
`resource_type` text NOT NULL,
|
||||
`resource_id` text,
|
||||
`resource_name` text,
|
||||
`details` text,
|
||||
`ip_address` text,
|
||||
`user_agent` text,
|
||||
`success` boolean NOT NULL,
|
||||
`error_message` text,
|
||||
`timestamp` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `audit_logs_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `c2s_tunnel_presets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`config` text NOT NULL,
|
||||
`platform` text,
|
||||
`computer_name` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `c2s_tunnel_presets_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `command_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`command` text NOT NULL,
|
||||
`executed_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `command_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `dashboard_service_links` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`label` text NOT NULL,
|
||||
`url` text NOT NULL,
|
||||
`order` int NOT NULL DEFAULT 0,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `dashboard_service_links_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `dashboard_service_links_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `dismissed_alerts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`alert_id` text NOT NULL,
|
||||
`dismissed_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `dismissed_alerts_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `file_manager_pinned` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`pinned_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `file_manager_pinned_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `file_manager_recent` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`last_opened` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `file_manager_recent_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `file_manager_shortcuts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`path` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `file_manager_shortcuts_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `homepage_items` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`type_id` text NOT NULL,
|
||||
`title` text,
|
||||
`config` text NOT NULL DEFAULT ('{}'),
|
||||
`folder_id` int,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `homepage_items_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `homepage_items_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `homepage_layouts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`layout` text NOT NULL DEFAULT ('{}'),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `homepage_layouts_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `homepage_layouts_user_id_unique` UNIQUE(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_access` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`role_id` int,
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
`permission_level` text NOT NULL DEFAULT ('connect'),
|
||||
`expires_at` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_accessed_at` text,
|
||||
`access_count` int NOT NULL DEFAULT 0,
|
||||
CONSTRAINT `host_access_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_health_checks` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`checks` text NOT NULL,
|
||||
`interval_seconds` int NOT NULL DEFAULT 300,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `host_health_checks_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_host_health_checks_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_health_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`check_id` text NOT NULL,
|
||||
`ts` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`ok` boolean NOT NULL,
|
||||
`latency_ms` int,
|
||||
`detail` text,
|
||||
CONSTRAINT `host_health_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_metrics_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`ts` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`cpu_percent` double,
|
||||
`mem_percent` double,
|
||||
`disk_percent` double,
|
||||
`net_rx_bytes` int,
|
||||
`net_tx_bytes` int,
|
||||
CONSTRAINT `host_metrics_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `host_metrics_preferences` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`layout` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `host_metrics_preferences_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_host_metrics_prefs_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_data` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`connection_type` text NOT NULL DEFAULT ('ssh'),
|
||||
`name` varchar(255),
|
||||
`ip` text NOT NULL,
|
||||
`port` int NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`folder` text,
|
||||
`tags` text,
|
||||
`pin` boolean NOT NULL DEFAULT false,
|
||||
`auth_type` text NOT NULL,
|
||||
`use_warpgate` boolean NOT NULL DEFAULT false,
|
||||
`share_ssh_auth` boolean NOT NULL DEFAULT false,
|
||||
`force_keyboard_interactive` text,
|
||||
`password` text,
|
||||
`key` text,
|
||||
`key_password` text,
|
||||
`key_type` text,
|
||||
`sudo_password` text,
|
||||
`autostart_password` text,
|
||||
`autostart_key` text,
|
||||
`autostart_key_password` text,
|
||||
`credential_id` int,
|
||||
`override_credential_username` boolean,
|
||||
`vault_profile_id` int,
|
||||
`enable_terminal` boolean NOT NULL DEFAULT true,
|
||||
`enable_session_logging` boolean NOT NULL DEFAULT true,
|
||||
`allow_session_sharing` boolean NOT NULL DEFAULT true,
|
||||
`enable_command_history` boolean NOT NULL DEFAULT true,
|
||||
`enable_tunnel` boolean NOT NULL DEFAULT true,
|
||||
`tunnel_connections` text,
|
||||
`jump_hosts` text,
|
||||
`enable_file_manager` boolean NOT NULL DEFAULT true,
|
||||
`scp_legacy` boolean NOT NULL DEFAULT false,
|
||||
`enable_docker` boolean NOT NULL DEFAULT false,
|
||||
`enable_tmux_monitor` boolean NOT NULL DEFAULT false,
|
||||
`show_terminal_in_sidebar` boolean NOT NULL DEFAULT true,
|
||||
`show_file_manager_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`show_tunnel_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`show_docker_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`show_server_stats_in_sidebar` boolean NOT NULL DEFAULT false,
|
||||
`default_path` text,
|
||||
`stats_config` text,
|
||||
`docker_config` text,
|
||||
`enable_proxmox` boolean NOT NULL DEFAULT false,
|
||||
`proxmox_config` text,
|
||||
`terminal_config` text,
|
||||
`quick_actions` text,
|
||||
`notes` text,
|
||||
`enable_ssh` boolean NOT NULL DEFAULT true,
|
||||
`enable_rdp` boolean NOT NULL DEFAULT false,
|
||||
`enable_vnc` boolean NOT NULL DEFAULT false,
|
||||
`enable_telnet` boolean NOT NULL DEFAULT false,
|
||||
`ssh_port` int DEFAULT 22,
|
||||
`rdp_port` int DEFAULT 3389,
|
||||
`vnc_port` int DEFAULT 5900,
|
||||
`telnet_port` int DEFAULT 23,
|
||||
`rdp_credential_id` int,
|
||||
`rdp_user` text,
|
||||
`rdp_password` text,
|
||||
`rdp_domain` text,
|
||||
`rdp_security` text,
|
||||
`rdp_ignore_cert` boolean DEFAULT false,
|
||||
`vnc_credential_id` int,
|
||||
`vnc_password` text,
|
||||
`vnc_user` text,
|
||||
`telnet_user` text,
|
||||
`telnet_password` text,
|
||||
`telnet_credential_id` int,
|
||||
`rdp_auth_type` text,
|
||||
`vnc_auth_type` text,
|
||||
`telnet_auth_type` text,
|
||||
`domain` text,
|
||||
`security` text,
|
||||
`ignore_cert` boolean DEFAULT false,
|
||||
`guacamole_config` text,
|
||||
`use_socks5` boolean,
|
||||
`socks5_host` text,
|
||||
`socks5_port` int,
|
||||
`socks5_username` text,
|
||||
`socks5_password` text,
|
||||
`socks5_proxy_chain` text,
|
||||
`connection_origin` text,
|
||||
`mac_address` text,
|
||||
`wol_broadcast_address` text,
|
||||
`port_knock_sequence` text,
|
||||
`host_key_fingerprint` text,
|
||||
`host_key_type` text,
|
||||
`host_key_algorithm` text DEFAULT ('sha256'),
|
||||
`host_key_first_seen` text,
|
||||
`host_key_last_verified` text,
|
||||
`host_key_changed_count` int DEFAULT 0,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_data_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `ssh_data_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `network_topology` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`topology` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `network_topology_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `notification_channels` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`type` text NOT NULL,
|
||||
`config` text NOT NULL,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `notification_channels_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `opkssh_tokens` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`ssh_cert` text NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`email` text,
|
||||
`sub` text,
|
||||
`issuer` text,
|
||||
`audience` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_used` text,
|
||||
CONSTRAINT `opkssh_tokens_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_opkssh_tokens_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `recent_activity` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`type` text NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`host_name` text,
|
||||
`timestamp` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `recent_activity_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `roles` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`display_name` text NOT NULL,
|
||||
`description` text,
|
||||
`is_system` boolean NOT NULL DEFAULT false,
|
||||
`permissions` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `roles_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `roles_name_unique` UNIQUE(`name`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session_recordings` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`username` text,
|
||||
`access_id` int,
|
||||
`started_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`ended_at` text,
|
||||
`duration` int,
|
||||
`commands` text,
|
||||
`dangerous_actions` text,
|
||||
`recording_path` text,
|
||||
`protocol` varchar(255) NOT NULL DEFAULT 'ssh',
|
||||
`format` text NOT NULL DEFAULT ('text'),
|
||||
`terminated_by_owner` boolean DEFAULT false,
|
||||
`termination_reason` text,
|
||||
CONSTRAINT `session_recordings_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session_share_participants` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`share_id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`guest_label` text,
|
||||
`joined_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`left_at` text,
|
||||
CONSTRAINT `session_share_participants_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session_shares` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`owner_user_id` varchar(255) NOT NULL,
|
||||
`protocol` varchar(255) NOT NULL,
|
||||
`session_id` text NOT NULL,
|
||||
`tab_instance_id` text,
|
||||
`share_type` text NOT NULL,
|
||||
`target_user_id` varchar(255),
|
||||
`link_token` varchar(255),
|
||||
`permission_level` text NOT NULL DEFAULT ('read-only'),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`revoked_at` text,
|
||||
`last_joined_at` text,
|
||||
`join_count` int NOT NULL DEFAULT 0,
|
||||
CONSTRAINT `session_shares_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `session_shares_link_token_unique` UNIQUE(`link_token`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sessions` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`jwt_token` text NOT NULL,
|
||||
`device_type` text NOT NULL,
|
||||
`device_info` text NOT NULL,
|
||||
`oidc_sub` text,
|
||||
`oidc_sid` text,
|
||||
`sso_provider_id` int,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_active_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sessions_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `settings` (
|
||||
`key` varchar(255) NOT NULL,
|
||||
`value` text NOT NULL,
|
||||
CONSTRAINT `settings_key` PRIMARY KEY(`key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `shared_host_auth_overrides` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`protocol` varchar(255) NOT NULL DEFAULT 'ssh',
|
||||
`credential_id` int NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `shared_host_auth_overrides_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `shared_host_auth_overrides_host_user_protocol_unique` UNIQUE(`host_id`,`user_id`,`protocol`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `shared_host_secrets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_access_id` int NOT NULL,
|
||||
`target_user_id` varchar(255) NOT NULL,
|
||||
`protocol` varchar(255) NOT NULL DEFAULT 'ssh',
|
||||
`source_type` text NOT NULL DEFAULT ('credential'),
|
||||
`original_credential_id` int,
|
||||
`encrypted_username` text,
|
||||
`encrypted_auth_type` text,
|
||||
`encrypted_password` text,
|
||||
`encrypted_key` text,
|
||||
`encrypted_key_password` text,
|
||||
`encrypted_key_type` text,
|
||||
`encrypted_domain` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `shared_host_secrets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_shared_host_secrets_scope` UNIQUE(`host_access_id`,`target_user_id`,`protocol`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snippet_access` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`snippet_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`role_id` int,
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
`permission_level` text NOT NULL DEFAULT ('view'),
|
||||
`expires_at` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `snippet_access_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snippet_folders` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `snippet_folders_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `snippet_folders_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `snippets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`content` text NOT NULL,
|
||||
`description` text,
|
||||
`folder` text,
|
||||
`order` int NOT NULL DEFAULT 0,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`host_filter` text,
|
||||
CONSTRAINT `snippets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `snippets_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_credential_usage` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`credential_id` int NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`used_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_credential_usage_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_credentials` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`folder` text,
|
||||
`tags` text,
|
||||
`auth_type` text NOT NULL,
|
||||
`username` text,
|
||||
`password` text,
|
||||
`key` text,
|
||||
`private_key` text,
|
||||
`public_key` text,
|
||||
`key_password` text,
|
||||
`key_type` text,
|
||||
`detected_key_type` text,
|
||||
`cert_public_key` text,
|
||||
`usage_count` int NOT NULL DEFAULT 0,
|
||||
`last_used` text,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_credentials_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `ssh_credentials_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ssh_folders` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`credential_id` int,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ssh_folders_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `ssh_folders_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sso_providers` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`type` text NOT NULL,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`display_order` int NOT NULL DEFAULT 0,
|
||||
`config` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sso_providers_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sync_tombstones` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`entity_type` text NOT NULL,
|
||||
`sync_id` varchar(255) NOT NULL,
|
||||
`deleted_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sync_tombstones_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `termix_identities` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`handle` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `termix_identities_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `termix_identities_user_id_unique` UNIQUE(`user_id`),
|
||||
CONSTRAINT `termix_identities_handle_unique` UNIQUE(`handle`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `termix_identity_ca` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`identity_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`validity_days` int NOT NULL DEFAULT 90,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `termix_identity_ca_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `termix_identity_ca_identity_id_unique` UNIQUE(`identity_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `termix_identity_keys` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`identity_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`key_type` text NOT NULL,
|
||||
`algorithm` text NOT NULL,
|
||||
`label` text,
|
||||
`comment` text,
|
||||
`source` text NOT NULL DEFAULT ('manual'),
|
||||
`credential_id` int,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `termix_identity_keys_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `tmux_session_tags` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`session_name` text NOT NULL,
|
||||
`tag` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `tmux_session_tags_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `transfer_recent` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`source_host_id` int NOT NULL,
|
||||
`dest_host_id` int NOT NULL,
|
||||
`dest_path` text NOT NULL,
|
||||
`dest_path_label` text NOT NULL,
|
||||
`last_used` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `transfer_recent_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `trusted_devices` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`device_fingerprint` text NOT NULL,
|
||||
`device_type` text NOT NULL,
|
||||
`device_info` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_used_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `trusted_devices_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_open_tabs` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`tab_type` text NOT NULL,
|
||||
`host_id` int,
|
||||
`label` text NOT NULL,
|
||||
`tab_order` int NOT NULL DEFAULT 0,
|
||||
`backend_session_id` text,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_open_tabs_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`reopen_tabs_on_login` boolean NOT NULL DEFAULT false,
|
||||
`theme` text,
|
||||
`font_size` text,
|
||||
`accent_color` text,
|
||||
`language` text,
|
||||
`storage_mode` text,
|
||||
`command_autocomplete` boolean,
|
||||
`command_palette_enabled` boolean,
|
||||
`show_host_tags` boolean,
|
||||
`host_tray_on_click` boolean,
|
||||
`pin_app_rail` boolean,
|
||||
`expand_app_rail_on_hover` boolean,
|
||||
`folders_collapsed` boolean,
|
||||
`confirm_snippet_execution` boolean,
|
||||
`disable_update_check` boolean,
|
||||
`confirm_tab_close` boolean,
|
||||
`hidden_rail_tabs` text,
|
||||
`compact_host_view` boolean,
|
||||
`status_color_scheme` text,
|
||||
`custom_themes` text,
|
||||
`custom_keybindings` text,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_roles` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`role_id` int NOT NULL,
|
||||
`granted_by` varchar(255),
|
||||
`granted_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_roles_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_user_roles_user_role` UNIQUE(`user_id`,`role_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `users` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`password_hash` text NOT NULL,
|
||||
`is_admin` boolean NOT NULL DEFAULT false,
|
||||
`is_oidc` boolean NOT NULL DEFAULT false,
|
||||
`oidc_identifier` text,
|
||||
`sso_provider_id` int,
|
||||
`client_id` text,
|
||||
`client_secret` text,
|
||||
`issuer_url` text,
|
||||
`authorization_url` text,
|
||||
`token_url` text,
|
||||
`identifier_path` text,
|
||||
`name_path` text,
|
||||
`scopes` text DEFAULT ('openid email profile'),
|
||||
`totp_secret` text,
|
||||
`totp_enabled` boolean NOT NULL DEFAULT false,
|
||||
`totp_backup_codes` text,
|
||||
`registered_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`donation_modal_dismissed` boolean NOT NULL DEFAULT false,
|
||||
CONSTRAINT `users_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `vault_profiles` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`folder` text,
|
||||
`tags` text,
|
||||
`vault_addr` text NOT NULL,
|
||||
`vault_namespace` text,
|
||||
`oidc_mount` text,
|
||||
`oidc_role` text,
|
||||
`ssh_mount` text,
|
||||
`ssh_role` text NOT NULL,
|
||||
`valid_principals` text,
|
||||
`key_type` text,
|
||||
`shared` boolean NOT NULL DEFAULT false,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `vault_profiles_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `vault_profiles_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `vault_tokens` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`profile_id` int NOT NULL,
|
||||
`ssh_cert` text NOT NULL,
|
||||
`private_key` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`expires_at` text NOT NULL,
|
||||
`last_used` text,
|
||||
CONSTRAINT `vault_tokens_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_vault_tokens_user_profile` UNIQUE(`user_id`,`profile_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `webauthn_credentials` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`credential_id` text NOT NULL,
|
||||
`public_key` text NOT NULL,
|
||||
`counter` int NOT NULL DEFAULT 0,
|
||||
`device_type` text,
|
||||
`backed_up` boolean NOT NULL DEFAULT false,
|
||||
`transports` text,
|
||||
`user_verification` text NOT NULL DEFAULT ('preferred'),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_used_at` text,
|
||||
CONSTRAINT `webauthn_credentials_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `alert_firings` ADD CONSTRAINT `alert_firings_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_firings` ADD CONSTRAINT `alert_firings_rule_id_alert_rules_id_fk` FOREIGN KEY (`rule_id`) REFERENCES `alert_rules`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rule_channels` ADD CONSTRAINT `alert_rule_channels_rule_id_alert_rules_id_fk` FOREIGN KEY (`rule_id`) REFERENCES `alert_rules`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rule_channels` ADD CONSTRAINT `alert_rule_channels_channel_id_notification_channels_id_fk` FOREIGN KEY (`channel_id`) REFERENCES `notification_channels`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` ADD CONSTRAINT `alert_rules_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` ADD CONSTRAINT `alert_rules_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `api_keys` ADD CONSTRAINT `api_keys_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` ADD CONSTRAINT `audit_logs_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `c2s_tunnel_presets` ADD CONSTRAINT `c2s_tunnel_presets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `command_history` ADD CONSTRAINT `command_history_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `command_history` ADD CONSTRAINT `command_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` ADD CONSTRAINT `dashboard_service_links_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `dismissed_alerts` ADD CONSTRAINT `dismissed_alerts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_pinned` ADD CONSTRAINT `file_manager_pinned_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_pinned` ADD CONSTRAINT `file_manager_pinned_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_recent` ADD CONSTRAINT `file_manager_recent_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_recent` ADD CONSTRAINT `file_manager_recent_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_shortcuts` ADD CONSTRAINT `file_manager_shortcuts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_shortcuts` ADD CONSTRAINT `file_manager_shortcuts_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `homepage_items` ADD CONSTRAINT `homepage_items_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `homepage_layouts` ADD CONSTRAINT `homepage_layouts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_access` ADD CONSTRAINT `host_access_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` ADD CONSTRAINT `host_health_checks_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` ADD CONSTRAINT `host_health_checks_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_history` ADD CONSTRAINT `host_health_history_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_health_history` ADD CONSTRAINT `host_health_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_history` ADD CONSTRAINT `host_metrics_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` ADD CONSTRAINT `host_metrics_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` ADD CONSTRAINT `host_metrics_preferences_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_vault_profile_id_vault_profiles_id_fk` FOREIGN KEY (`vault_profile_id`) REFERENCES `vault_profiles`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_rdp_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`rdp_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_vnc_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`vnc_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_telnet_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`telnet_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `network_topology` ADD CONSTRAINT `network_topology_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `notification_channels` ADD CONSTRAINT `notification_channels_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` ADD CONSTRAINT `opkssh_tokens_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` ADD CONSTRAINT `opkssh_tokens_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `recent_activity` ADD CONSTRAINT `recent_activity_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `recent_activity` ADD CONSTRAINT `recent_activity_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` ADD CONSTRAINT `session_recordings_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` ADD CONSTRAINT `session_recordings_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` ADD CONSTRAINT `session_recordings_access_id_host_access_id_fk` FOREIGN KEY (`access_id`) REFERENCES `host_access`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_share_participants` ADD CONSTRAINT `session_share_participants_share_id_session_shares_id_fk` FOREIGN KEY (`share_id`) REFERENCES `session_shares`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_share_participants` ADD CONSTRAINT `session_share_participants_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` ADD CONSTRAINT `session_shares_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` ADD CONSTRAINT `session_shares_owner_user_id_users_id_fk` FOREIGN KEY (`owner_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` ADD CONSTRAINT `session_shares_target_user_id_users_id_fk` FOREIGN KEY (`target_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `sessions` ADD CONSTRAINT `sessions_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` ADD CONSTRAINT `shared_host_auth_overrides_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` ADD CONSTRAINT `shared_host_auth_overrides_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` ADD CONSTRAINT `shared_host_auth_overrides_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` ADD CONSTRAINT `shared_host_secrets_host_access_id_host_access_id_fk` FOREIGN KEY (`host_access_id`) REFERENCES `host_access`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` ADD CONSTRAINT `shared_host_secrets_target_user_id_users_id_fk` FOREIGN KEY (`target_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` ADD CONSTRAINT `shared_host_secrets_original_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`original_credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_snippet_id_snippets_id_fk` FOREIGN KEY (`snippet_id`) REFERENCES `snippets`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` ADD CONSTRAINT `snippet_access_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_folders` ADD CONSTRAINT `snippet_folders_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `snippets` ADD CONSTRAINT `snippets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credential_usage` ADD CONSTRAINT `ssh_credential_usage_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credential_usage` ADD CONSTRAINT `ssh_credential_usage_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credential_usage` ADD CONSTRAINT `ssh_credential_usage_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD CONSTRAINT `ssh_credentials_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD CONSTRAINT `ssh_folders_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD CONSTRAINT `ssh_folders_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `sync_tombstones` ADD CONSTRAINT `sync_tombstones_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identities` ADD CONSTRAINT `termix_identities_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` ADD CONSTRAINT `termix_identity_ca_identity_id_termix_identities_id_fk` FOREIGN KEY (`identity_id`) REFERENCES `termix_identities`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` ADD CONSTRAINT `termix_identity_ca_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` ADD CONSTRAINT `termix_identity_keys_identity_id_termix_identities_id_fk` FOREIGN KEY (`identity_id`) REFERENCES `termix_identities`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` ADD CONSTRAINT `termix_identity_keys_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` ADD CONSTRAINT `termix_identity_keys_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `tmux_session_tags` ADD CONSTRAINT `tmux_session_tags_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `tmux_session_tags` ADD CONSTRAINT `tmux_session_tags_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `transfer_recent` ADD CONSTRAINT `transfer_recent_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `transfer_recent` ADD CONSTRAINT `transfer_recent_source_host_id_ssh_data_id_fk` FOREIGN KEY (`source_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `transfer_recent` ADD CONSTRAINT `transfer_recent_dest_host_id_ssh_data_id_fk` FOREIGN KEY (`dest_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` ADD CONSTRAINT `trusted_devices_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` ADD CONSTRAINT `user_open_tabs_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` ADD CONSTRAINT `user_open_tabs_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD CONSTRAINT `user_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` ADD CONSTRAINT `vault_profiles_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` ADD CONSTRAINT `vault_tokens_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` ADD CONSTRAINT `vault_tokens_profile_id_vault_profiles_id_fk` FOREIGN KEY (`profile_id`) REFERENCES `vault_profiles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `webauthn_credentials` ADD CONSTRAINT `webauthn_credentials_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,10 +0,0 @@
|
||||
CREATE TABLE `host_sidebar_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `host_sidebar_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `sort_order` int;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD `sort_order` int;--> statement-breakpoint
|
||||
ALTER TABLE `host_sidebar_preferences` ADD CONSTRAINT `host_sidebar_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,10 +0,0 @@
|
||||
CREATE TABLE `credential_sidebar_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `credential_sidebar_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD `pin` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD `sort_order` int;--> statement-breakpoint
|
||||
ALTER TABLE `credential_sidebar_preferences` ADD CONSTRAINT `credential_sidebar_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `snippets` ADD `is_note` boolean DEFAULT false NOT NULL;
|
||||
@@ -1,28 +0,0 @@
|
||||
CREATE TABLE `proxmox_node_history` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`ts` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`cpu_percent` double,
|
||||
`mem_percent` double,
|
||||
`disk_percent` double,
|
||||
`net_rx_bytes` int,
|
||||
`net_tx_bytes` int,
|
||||
CONSTRAINT `proxmox_node_history_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `proxmox_stats_preferences` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`layout` text NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `proxmox_stats_preferences_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_proxmox_stats_prefs_user_host` UNIQUE(`user_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `enable_proxmox_stats` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `proxmox_stats_config` text;--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_node_history` ADD CONSTRAINT `proxmox_node_history_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` ADD CONSTRAINT `proxmox_stats_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` ADD CONSTRAINT `proxmox_stats_preferences_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `ssh_data` ADD `enable_terminal_toolbar` boolean DEFAULT true NOT NULL;
|
||||
@@ -1,45 +0,0 @@
|
||||
CREATE TABLE `fleet_inventory` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`os_pretty_name` text,
|
||||
`kernel` text,
|
||||
`architecture` text,
|
||||
`hostname` text,
|
||||
`uptime_seconds` int,
|
||||
`ip` text,
|
||||
`package_manager` text,
|
||||
`collected_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `fleet_inventory_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_fleet_inventory_host` UNIQUE(`host_id`,`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `fleet_members` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`fleet_id` int NOT NULL,
|
||||
`host_id` int NOT NULL,
|
||||
`added_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `fleet_members_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_fleet_members_fleet_host` UNIQUE(`fleet_id`,`host_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `fleets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`tag_rules` text,
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `fleets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `fleets_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `fleet_inventory` ADD CONSTRAINT `fleet_inventory_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleet_inventory` ADD CONSTRAINT `fleet_inventory_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleet_members` ADD CONSTRAINT `fleet_members_fleet_id_fleets_id_fk` FOREIGN KEY (`fleet_id`) REFERENCES `fleets`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleet_members` ADD CONSTRAINT `fleet_members_host_id_ssh_data_id_fk` FOREIGN KEY (`host_id`) REFERENCES `ssh_data`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `fleets` ADD CONSTRAINT `fleets_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE `ssh_data` ADD `parent_host_id` int;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD CONSTRAINT `ssh_data_parent_host_id_ssh_data_id_fk` FOREIGN KEY (`parent_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE set null ON UPDATE no action;
|
||||
@@ -1,18 +0,0 @@
|
||||
CREATE TABLE `user_workspaces` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` text,
|
||||
`icon` text,
|
||||
`kind` text NOT NULL DEFAULT ('manual'),
|
||||
`is_default` boolean NOT NULL DEFAULT false,
|
||||
`payload` text NOT NULL DEFAULT ('{}'),
|
||||
`sync_id` varchar(255),
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_used_at` text,
|
||||
CONSTRAINT `user_workspaces_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `user_workspaces_sync_id_unique` UNIQUE(`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `user_workspaces` ADD CONSTRAINT `user_workspaces_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,26 +0,0 @@
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `expires_at` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` MODIFY COLUMN `action` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` MODIFY COLUMN `resource_type` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `audit_logs` MODIFY COLUMN `timestamp` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_access` MODIFY COLUMN `expires_at` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `recent_activity` MODIFY COLUMN `timestamp` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `sessions` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` MODIFY COLUMN `expires_at` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` MODIFY COLUMN `expires_at` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `webauthn_credentials` MODIFY COLUMN `credential_id` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_timestamp` ON `audit_logs` (`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_user_ts` ON `audit_logs` (`user_id`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_action_ts` ON `audit_logs` (`action`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_logs_resource_ts` ON `audit_logs` (`resource_type`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_user_id` ON `host_access` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_role_id` ON `host_access` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_host_id` ON `host_access` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_host_access_expires_at` ON `host_access` (`expires_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_data_user_id` ON `ssh_data` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_data_parent_host` ON `ssh_data` (`parent_host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_data_credential` ON `ssh_data` (`credential_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_sessions_user_id` ON `sessions` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_sessions_expires_at` ON `sessions` (`expires_at`);
|
||||
@@ -1,8 +0,0 @@
|
||||
CREATE TABLE `ui_preferences` (
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ui_preferences_user_id` PRIMARY KEY(`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ui_preferences` ADD CONSTRAINT `ui_preferences_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,32 +0,0 @@
|
||||
ALTER TABLE `alert_firings` MODIFY COLUMN `fired_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_recordings` MODIFY COLUMN `started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` MODIFY COLUMN `session_id` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
CREATE INDEX `idx_alert_firings_rule` ON `alert_firings` (`rule_id`,`fired_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_alert_firings_host` ON `alert_firings` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_api_keys_user_id` ON `api_keys` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_command_history_user_host` ON `command_history` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_dismissed_alerts_user_id` ON `dismissed_alerts` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_file_manager_pinned_user` ON `file_manager_pinned` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_file_manager_recent_user` ON `file_manager_recent` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_file_manager_shortcuts_user` ON `file_manager_shortcuts` (`user_id`,`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_fleet_inventory_user` ON `fleet_inventory` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_fleet_members_host` ON `fleet_members` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_homepage_items_user_id` ON `homepage_items` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_recent_activity_user_ts` ON `recent_activity` (`user_id`,`timestamp`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_recordings_user_started` ON `session_recordings` (`user_id`,`started_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_recordings_host` ON `session_recordings` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_shares_session_id` ON `session_shares` (`session_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_session_shares_host_id` ON `session_shares` (`host_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippet_access_user_id` ON `snippet_access` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippet_access_snippet_id` ON `snippet_access` (`snippet_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippet_access_role_id` ON `snippet_access` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_snippets_user_id` ON `snippets` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_credential_usage_credential` ON `ssh_credential_usage` (`credential_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_credential_usage_user` ON `ssh_credential_usage` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_credentials_user_id` ON `ssh_credentials` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ssh_folders_user_id` ON `ssh_folders` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_transfer_recent_user` ON `transfer_recent` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_trusted_devices_user_id` ON `trusted_devices` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_open_tabs_user_id` ON `user_open_tabs` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_roles_role_id` ON `user_roles` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_workspaces_user_id` ON `user_workspaces` (`user_id`);
|
||||
@@ -1,224 +0,0 @@
|
||||
CREATE TABLE `ai_conversations` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`title` text,
|
||||
`provider_id` int,
|
||||
`model` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_conversations_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ai_messages` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`conversation_id` int NOT NULL,
|
||||
`role` text NOT NULL,
|
||||
`content` text NOT NULL DEFAULT (''),
|
||||
`tool_calls` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_messages_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ai_proposals` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`conversation_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`kind` text NOT NULL,
|
||||
`summary` text,
|
||||
`payload` text NOT NULL DEFAULT ('{}'),
|
||||
`status` varchar(255) NOT NULL DEFAULT 'pending',
|
||||
`applied_at` text,
|
||||
`result_summary` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_proposals_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `ai_providers` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`provider_type` text NOT NULL,
|
||||
`label` varchar(255) NOT NULL,
|
||||
`base_url` text,
|
||||
`api_key` text,
|
||||
`api_key_prefix` text,
|
||||
`default_model` text,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `ai_providers_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_ai_providers_user_label` UNIQUE(`user_id`,`label`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_channels` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`channel_id` int NOT NULL,
|
||||
CONSTRAINT `automation_channels_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_automation_channels_pair` UNIQUE(`automation_id`,`channel_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_run_steps` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`run_id` int NOT NULL,
|
||||
`step_index` int NOT NULL,
|
||||
`step_id` text NOT NULL,
|
||||
`step_type` text NOT NULL,
|
||||
`status` varchar(255) NOT NULL,
|
||||
`started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`finished_at` text,
|
||||
`output` text,
|
||||
`error` text,
|
||||
`truncated` boolean NOT NULL DEFAULT false,
|
||||
CONSTRAINT `automation_run_steps_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_runs` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`trigger_type` text NOT NULL,
|
||||
`trigger_context` text,
|
||||
`status` varchar(255) NOT NULL,
|
||||
`started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`finished_at` text,
|
||||
`duration_ms` int,
|
||||
`error` text,
|
||||
`dry_run` boolean NOT NULL DEFAULT false,
|
||||
`parent_run_id` int,
|
||||
CONSTRAINT `automation_runs_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_schedules` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`cron` text,
|
||||
`interval_seconds` int,
|
||||
`timezone` text,
|
||||
`next_due_at` varchar(255),
|
||||
`last_tick_at` text,
|
||||
CONSTRAINT `automation_schedules_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_automation_schedules_automation` UNIQUE(`automation_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automation_trigger_state` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`automation_id` int NOT NULL,
|
||||
`state_key` varchar(255) NOT NULL,
|
||||
`breach_started_at` text,
|
||||
`last_fired_at` text,
|
||||
`last_value` double,
|
||||
`last_observed_state` text,
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `automation_trigger_state_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_automation_trigger_state_key` UNIQUE(`automation_id`,`state_key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `automations` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text,
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`definition` text NOT NULL,
|
||||
`definition_version` int NOT NULL DEFAULT 1,
|
||||
`concurrency_policy` text NOT NULL DEFAULT ('skip'),
|
||||
`max_run_seconds` int NOT NULL DEFAULT 300,
|
||||
`dry_run` boolean NOT NULL DEFAULT false,
|
||||
`last_run_at` text,
|
||||
`last_run_status` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `automations_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `alert_rules` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `c2s_tunnel_presets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `c2s_tunnel_presets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `credential_sidebar_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` MODIFY COLUMN `label` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `dashboard_service_links` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `file_manager_shortcuts` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `fleets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `fleets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `homepage_items` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `homepage_items` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `homepage_layouts` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_access` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_health_checks` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_metrics_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_sidebar_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `network_topology` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `network_topology` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `notification_channels` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `opkssh_tokens` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `proxmox_stats_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `roles` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `roles` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `session_shares` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sessions` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippet_access` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippet_folders` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippet_folders` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippets` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `snippets` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sso_providers` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sso_providers` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identities` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identities` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_ca` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` MODIFY COLUMN `label` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `termix_identity_keys` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `tmux_session_tags` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ui_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `label` varchar(255) NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_workspaces` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_workspaces` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` MODIFY COLUMN `updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `vault_tokens` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `webauthn_credentials` MODIFY COLUMN `created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD `ai_assistant_enabled` boolean;--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD `ai_read_only_commands` boolean;--> statement-breakpoint
|
||||
ALTER TABLE `ai_conversations` ADD CONSTRAINT `ai_conversations_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_messages` ADD CONSTRAINT `ai_messages_conversation_id_ai_conversations_id_fk` FOREIGN KEY (`conversation_id`) REFERENCES `ai_conversations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_proposals` ADD CONSTRAINT `ai_proposals_conversation_id_ai_conversations_id_fk` FOREIGN KEY (`conversation_id`) REFERENCES `ai_conversations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_proposals` ADD CONSTRAINT `ai_proposals_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `ai_providers` ADD CONSTRAINT `ai_providers_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_channels` ADD CONSTRAINT `automation_channels_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_channels` ADD CONSTRAINT `automation_channels_channel_id_notification_channels_id_fk` FOREIGN KEY (`channel_id`) REFERENCES `notification_channels`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_run_steps` ADD CONSTRAINT `automation_run_steps_run_id_automation_runs_id_fk` FOREIGN KEY (`run_id`) REFERENCES `automation_runs`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_runs` ADD CONSTRAINT `automation_runs_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_runs` ADD CONSTRAINT `automation_runs_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_schedules` ADD CONSTRAINT `automation_schedules_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automation_trigger_state` ADD CONSTRAINT `automation_trigger_state_automation_id_automations_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automations`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `automations` ADD CONSTRAINT `automations_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_conversations_user` ON `ai_conversations` (`user_id`,`updated_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_messages_conversation` ON `ai_messages` (`conversation_id`,`created_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_proposals_user` ON `ai_proposals` (`user_id`,`status`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_ai_proposals_conversation` ON `ai_proposals` (`conversation_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_run_steps_run` ON `automation_run_steps` (`run_id`,`step_index`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_runs_automation` ON `automation_runs` (`automation_id`,`started_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_runs_user` ON `automation_runs` (`user_id`,`started_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automation_schedules_due` ON `automation_schedules` (`next_due_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_automations_user` ON `automations` (`user_id`,`enabled`);
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE `user_preferences` ADD `terminal_defaults` text;--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` ADD `rdp_defaults` text;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `user_preferences` ADD `terminal_macros` text;
|
||||
@@ -1,34 +0,0 @@
|
||||
CREATE TABLE `collab_room_members` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`room_id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`room_role` text NOT NULL DEFAULT ('member'),
|
||||
`added_by` varchar(255),
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `collab_room_members_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_collab_room_members_room_user` UNIQUE(`room_id`,`user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `collab_rooms` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`owner_user_id` varchar(255) NOT NULL,
|
||||
`persistent` boolean NOT NULL DEFAULT false,
|
||||
`presenter_user_id` varchar(255),
|
||||
`stage_protocol` text,
|
||||
`stage_host_id` int,
|
||||
`stage_share_id` varchar(255),
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`ended_at` text,
|
||||
CONSTRAINT `collab_rooms_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `collab_room_members` ADD CONSTRAINT `collab_room_members_room_id_collab_rooms_id_fk` FOREIGN KEY (`room_id`) REFERENCES `collab_rooms`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `collab_room_members` ADD CONSTRAINT `collab_room_members_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `collab_room_members` ADD CONSTRAINT `collab_room_members_added_by_users_id_fk` FOREIGN KEY (`added_by`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `collab_rooms` ADD CONSTRAINT `collab_rooms_owner_user_id_users_id_fk` FOREIGN KEY (`owner_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `collab_rooms` ADD CONSTRAINT `collab_rooms_presenter_user_id_users_id_fk` FOREIGN KEY (`presenter_user_id`) REFERENCES `users`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `collab_rooms` ADD CONSTRAINT `collab_rooms_stage_host_id_ssh_data_id_fk` FOREIGN KEY (`stage_host_id`) REFERENCES `ssh_data`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `collab_rooms` ADD CONSTRAINT `collab_rooms_stage_share_id_session_shares_id_fk` FOREIGN KEY (`stage_share_id`) REFERENCES `session_shares`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_collab_room_members_user` ON `collab_room_members` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_collab_rooms_owner` ON `collab_rooms` (`owner_user_id`);
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE `collab_rooms` ADD `guest_link_token` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `collab_rooms` ADD CONSTRAINT `idx_collab_rooms_guest_token` UNIQUE(`guest_link_token`);
|
||||
@@ -1,15 +0,0 @@
|
||||
CREATE TABLE `secret_sources` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`kind` text NOT NULL DEFAULT ('onepassword-connect'),
|
||||
`base_url` text NOT NULL,
|
||||
`token` text NOT NULL,
|
||||
`shared` boolean NOT NULL DEFAULT false,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `secret_sources_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `secret_sources` ADD CONSTRAINT `secret_sources_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_secret_sources_user` ON `secret_sources` (`user_id`);
|
||||
@@ -1,42 +0,0 @@
|
||||
CREATE TABLE `credential_access` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`credential_id` int NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`role_id` int,
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
`permission_level` text NOT NULL DEFAULT ('use'),
|
||||
`expires_at` varchar(255),
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `credential_access_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `shared_credential_secrets` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`credential_access_id` int NOT NULL,
|
||||
`target_user_id` varchar(255) NOT NULL,
|
||||
`credential_id` int NOT NULL,
|
||||
`encrypted_username` text,
|
||||
`auth_type` text NOT NULL DEFAULT ('password'),
|
||||
`encrypted_password` text,
|
||||
`encrypted_key` text,
|
||||
`encrypted_key_password` text,
|
||||
`key_type` text,
|
||||
`public_key` text,
|
||||
`cert_public_key` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `shared_credential_secrets_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_shared_credential_secrets_scope` UNIQUE(`credential_access_id`,`target_user_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `credential_access` ADD CONSTRAINT `credential_access_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `credential_access` ADD CONSTRAINT `credential_access_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `credential_access` ADD CONSTRAINT `credential_access_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `credential_access` ADD CONSTRAINT `credential_access_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_credential_secrets` ADD CONSTRAINT `shared_cred_secrets_access_id_fk` FOREIGN KEY (`credential_access_id`) REFERENCES `credential_access`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_credential_secrets` ADD CONSTRAINT `shared_credential_secrets_target_user_id_users_id_fk` FOREIGN KEY (`target_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `shared_credential_secrets` ADD CONSTRAINT `shared_credential_secrets_credential_id_ssh_credentials_id_fk` FOREIGN KEY (`credential_id`) REFERENCES `ssh_credentials`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_credential_access_user_id` ON `credential_access` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_credential_access_role_id` ON `credential_access` (`role_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_credential_access_credential_id` ON `credential_access` (`credential_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_shared_credential_secrets_target` ON `shared_credential_secrets` (`target_user_id`,`credential_id`);
|
||||
@@ -1,22 +0,0 @@
|
||||
CREATE TABLE `folder_access` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`owner_user_id` varchar(255) NOT NULL,
|
||||
`folder` varchar(255) NOT NULL,
|
||||
`user_id` varchar(255),
|
||||
`role_id` int,
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
`permission_level` text NOT NULL DEFAULT ('connect'),
|
||||
`expires_at` varchar(255),
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `folder_access_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `folder` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `snippets` MODIFY COLUMN `folder` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `folder` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `vault_profiles` MODIFY COLUMN `folder` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `folder_access` ADD CONSTRAINT `folder_access_owner_user_id_users_id_fk` FOREIGN KEY (`owner_user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `folder_access` ADD CONSTRAINT `folder_access_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `folder_access` ADD CONSTRAINT `folder_access_role_id_roles_id_fk` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `folder_access` ADD CONSTRAINT `folder_access_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_folder_access_owner_folder` ON `folder_access` (`owner_user_id`,`folder`);
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE `ssh_data` ADD `enable_web_ui` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `web_ui_config` text;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `ssh_data` ADD `enable_ai_assistant` boolean DEFAULT false NOT NULL;
|
||||
@@ -1,51 +0,0 @@
|
||||
CREATE TABLE `plugin_install_counts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`registry_id` varchar(255) NOT NULL,
|
||||
`count` int NOT NULL DEFAULT 0,
|
||||
`source` text NOT NULL DEFAULT ('aggregate-telemetry'),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `plugin_install_counts_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_plugin_install_counts_plugin_registry` UNIQUE(`plugin_id`,`registry_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `plugin_permission_grants` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`capability` varchar(255) NOT NULL,
|
||||
`granted_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`granted_by` varchar(255) NOT NULL,
|
||||
CONSTRAINT `plugin_permission_grants_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_plugin_permission_grants_plugin_capability` UNIQUE(`plugin_id`,`capability`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `plugin_registries` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`url` text NOT NULL,
|
||||
`kind` text NOT NULL DEFAULT ('community'),
|
||||
`enabled` boolean NOT NULL DEFAULT true,
|
||||
`signing_key` text,
|
||||
`last_checked_at` text,
|
||||
`last_index_hash` text,
|
||||
CONSTRAINT `plugin_registries_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `plugins` (
|
||||
`id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`version` text NOT NULL,
|
||||
`tier` text NOT NULL DEFAULT ('available'),
|
||||
`source` text NOT NULL DEFAULT ('community'),
|
||||
`registry_id` varchar(255),
|
||||
`state` text NOT NULL DEFAULT ('disabled'),
|
||||
`installed_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`auto_update` boolean NOT NULL DEFAULT false,
|
||||
`manifest_json` text NOT NULL,
|
||||
CONSTRAINT `plugins_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `plugin_permission_grants` ADD CONSTRAINT `plugin_permission_grants_plugin_id_plugins_id_fk` FOREIGN KEY (`plugin_id`) REFERENCES `plugins`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `plugin_permission_grants` ADD CONSTRAINT `plugin_permission_grants_granted_by_users_id_fk` FOREIGN KEY (`granted_by`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_plugins_registry_id` ON `plugins` (`registry_id`);
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `user_preferences` ADD `show_pin_app_rail_button` boolean;
|
||||
@@ -1,11 +0,0 @@
|
||||
CREATE TABLE `plugin_storage` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`key` varchar(255) NOT NULL,
|
||||
`value` text NOT NULL,
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `plugin_storage_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_plugin_storage_plugin_key` UNIQUE(`plugin_id`,`key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `plugin_storage` ADD CONSTRAINT `plugin_storage_plugin_id_plugins_id_fk` FOREIGN KEY (`plugin_id`) REFERENCES `plugins`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,3 +0,0 @@
|
||||
DROP TABLE `alert_firings`;--> statement-breakpoint
|
||||
DROP TABLE `alert_rule_channels`;--> statement-breakpoint
|
||||
DROP TABLE `alert_rules`;
|
||||
@@ -1,3 +0,0 @@
|
||||
ALTER TABLE `plugin_permission_grants` MODIFY COLUMN `granted_by` varchar(255);--> statement-breakpoint
|
||||
ALTER TABLE `plugin_permission_grants` ADD `source` text DEFAULT ('admin') NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `plugins` ADD `last_error` text;
|
||||
@@ -1,11 +0,0 @@
|
||||
CREATE TABLE `plugin_migrations` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`migration_id` varchar(255) NOT NULL,
|
||||
`checksum` text NOT NULL,
|
||||
`applied_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `plugin_migrations_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_plugin_migrations_plugin_migration` UNIQUE(`plugin_id`,`migration_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `plugin_migrations` ADD CONSTRAINT `plugin_migrations_plugin_id_plugins_id_fk` FOREIGN KEY (`plugin_id`) REFERENCES `plugins`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,17 +0,0 @@
|
||||
CREATE TABLE `rbac_applied_defaults` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`role_name` varchar(255) NOT NULL,
|
||||
`permission` varchar(255) NOT NULL,
|
||||
`applied_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `rbac_applied_defaults_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_rbac_applied_defaults_role_permission` UNIQUE(`role_name`,`permission`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `rbac_known_permissions` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`permission` varchar(255) NOT NULL,
|
||||
`plugin_id` varchar(255),
|
||||
`first_seen_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `rbac_known_permissions_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_rbac_known_permissions_permission` UNIQUE(`permission`)
|
||||
);
|
||||
@@ -1,15 +0,0 @@
|
||||
CREATE TABLE `plugin_settings` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`scope` enum('admin','user','host','secret') NOT NULL,
|
||||
`scope_id` varchar(255),
|
||||
`key` varchar(255) NOT NULL,
|
||||
`value` text,
|
||||
`encrypted` boolean NOT NULL DEFAULT false,
|
||||
`updated_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `plugin_settings_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_plugin_settings_scope_key` UNIQUE(`plugin_id`,`scope`,`scope_id`,`key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `plugin_settings` ADD CONSTRAINT `plugin_settings_plugin_id_plugins_id_fk` FOREIGN KEY (`plugin_id`) REFERENCES `plugins`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_plugin_settings_plugin_scope` ON `plugin_settings` (`plugin_id`,`scope`);
|
||||
@@ -1,24 +0,0 @@
|
||||
CREATE TABLE `user_external_identities` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`provider_id` varchar(255) NOT NULL,
|
||||
`subject` varchar(255) NOT NULL,
|
||||
`email` text,
|
||||
`created_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_external_identities_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_user_external_identities_provider_subject` UNIQUE(`provider_id`,`subject`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user_second_factors` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`factor_id` varchar(255) NOT NULL,
|
||||
`enrolled_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `user_second_factors_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_user_second_factors_user_factor` UNIQUE(`user_id`,`plugin_id`,`factor_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `user_external_identities` ADD CONSTRAINT `user_external_identities_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `user_second_factors` ADD CONSTRAINT `user_second_factors_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_user_external_identities_user` ON `user_external_identities` (`user_id`);
|
||||
@@ -1,5 +0,0 @@
|
||||
-- user_workspaces moved to the workspaces plugin, whose first migration renames it
|
||||
-- to p_workspaces_workspaces. Dropping it here would lose every saved workspace,
|
||||
-- so this only stops drizzle tracking it. SELECT 1 because MySQL rejects an
|
||||
-- empty query.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- network_topology moved to the network-topology plugin, which adopts (renames)
|
||||
-- this table in its own migration before this drizzle migration would run.
|
||||
-- No DROP here: it would delete every row before the plugin's rename applies.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- snippets, snippet_folders and snippet_access moved to the snippets plugin
|
||||
-- (p_snippets_*), adopted by rename rather than dropped. A real DROP TABLE
|
||||
-- here would run before the plugin's adoption migration and delete every row.
|
||||
SELECT 1;
|
||||
@@ -1,2 +0,0 @@
|
||||
-- dropped, see plugin adoption (fleets plugin, migrations/mysql/0001_adopt_fleets.sql)
|
||||
SELECT 1;
|
||||
@@ -1,6 +0,0 @@
|
||||
-- proxmox_node_history and proxmox_stats_preferences moved to the proxmox
|
||||
-- plugin (p_proxmox_*), adopted by rename rather than dropped. The four
|
||||
-- ssh_data proxmox columns are copied into the plugin's host settings after
|
||||
-- plugins load, which is after this migration, so a real DROP COLUMN here
|
||||
-- would delete the data first. The columns stay in place, unused, until 3.0.0.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- file_manager_pinned, file_manager_recent, file_manager_shortcuts and
|
||||
-- transfer_recent are adopted (renamed, not dropped) by the file-manager
|
||||
-- plugin's own migration, which runs at plugin activation, after core's
|
||||
-- drizzle migrations. A DROP TABLE here would run first and delete the data.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- c2s_tunnel_presets moved to the tunnels plugin, whose first migration renames
|
||||
-- it to p_tunnels_presets. Dropping it here would lose every saved preset, so
|
||||
-- this only stops drizzle tracking it. SELECT 1 because MySQL rejects an
|
||||
-- empty query.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- command_history moved to the ssh-terminal plugin, whose first migration
|
||||
-- renames it to p_ssh_terminal_command_history. Dropping it here would lose
|
||||
-- every saved command, so this only stops drizzle tracking it. SELECT 1
|
||||
-- because MySQL rejects an empty query.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- tmux_session_tags moved to the tmux-monitor plugin, whose first migration
|
||||
-- renames it to p_tmux_monitor_session_tags. Dropping it here would lose
|
||||
-- every saved tag, so this only stops drizzle tracking it. SELECT 1 because
|
||||
-- MySQL rejects an empty query.
|
||||
SELECT 1;
|
||||
@@ -1,6 +0,0 @@
|
||||
-- session_shares, session_share_participants, collab_rooms and
|
||||
-- collab_room_members moved to the session-sharing plugin, whose first
|
||||
-- migration renames them. Dropping them here would lose every share and
|
||||
-- room, so this only stops drizzle tracking them. SELECT 1 because MySQL
|
||||
-- rejects an empty query.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- session_recordings moved to the session-recording plugin, whose first
|
||||
-- migration renames it. Dropping it here would lose every recording, so
|
||||
-- this only stops drizzle tracking it. SELECT 1 because MySQL rejects an
|
||||
-- empty query.
|
||||
SELECT 1;
|
||||
@@ -1,7 +0,0 @@
|
||||
-- The remote desktop host options (enable_rdp, enable_vnc, enable_telnet,
|
||||
-- the three ports, rdp_security, rdp_ignore_cert, security, ignore_cert,
|
||||
-- guacamole_config) and user_preferences.rdp_defaults moved to the
|
||||
-- remote-desktop plugin's settings. The copy runs after plugins load, which
|
||||
-- is after this migration, so a real DROP COLUMN here would delete the data
|
||||
-- first. The columns stay in place, unused, until 3.0.0.
|
||||
SELECT 1;
|
||||
@@ -1,9 +0,0 @@
|
||||
-- host_metrics_preferences, host_health_checks, host_health_history and
|
||||
-- host_metrics_history moved to the host-metrics plugin, which adopts them by
|
||||
-- rename in its own first migration. That runs after this one, so a real
|
||||
-- DROP TABLE here would delete every row first.
|
||||
SELECT 1;--> statement-breakpoint
|
||||
-- Status checks are core: the per-host switch and interval, copied out of
|
||||
-- stats_config at boot by host-status-config-migration.ts.
|
||||
ALTER TABLE `ssh_data` ADD `status_check_enabled` boolean DEFAULT true NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `status_check_interval` int;
|
||||
@@ -1,6 +0,0 @@
|
||||
-- ssh_data.stats_config split: its status half moved to status_check_enabled
|
||||
-- and status_check_interval, its metrics half to the host-metrics plugin's
|
||||
-- host settings. Both copies run at boot, after this migration, so a real
|
||||
-- DROP COLUMN here would delete the data first. The column stays in place,
|
||||
-- unused, until 3.0.0.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- ssh_data.enable_docker and docker_config moved to the docker plugin's host
|
||||
-- settings. The copy runs at boot, after this migration, so a real DROP
|
||||
-- COLUMN here would delete the data first. The columns stay in place,
|
||||
-- unused, until 3.0.0.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- The automation tables moved to the automations plugin, which renames them
|
||||
-- into its own namespace at activation. That runs after this migration, so a
|
||||
-- real DROP TABLE here would delete every automation first.
|
||||
SELECT 1;
|
||||
@@ -1,8 +0,0 @@
|
||||
-- The ai tables moved to the ai plugin, which renames them into its own
|
||||
-- namespace at activation, and ssh_data.enable_ai_assistant and the two
|
||||
-- user_preferences ai columns moved to its settings. Both run after this
|
||||
-- migration, so a real DROP here would delete the data first. The columns
|
||||
-- stay in place, unused, until 3.0.0. The timestamp and label type changes
|
||||
-- drizzle-kit also wrote are generator drift (see FINISH-LIST.md), not a
|
||||
-- change to the database, and are left out on purpose.
|
||||
SELECT 1;
|
||||
@@ -1,6 +0,0 @@
|
||||
-- dashboard_service_links, homepage_items and homepage_layouts moved to the
|
||||
-- homepage plugin, which adopts them by rename at activation (see
|
||||
-- plugins/homepage/migrations/mysql/0001_adopt_homepage_tables.sql).
|
||||
-- Dropping them here would delete every row before the plugin's migration
|
||||
-- ever runs, since this runs at boot before the plugins table exists.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- mac_address and wol_broadcast_address move to the wake-on-lan plugin's
|
||||
-- host settings at boot, after this migration runs. Dropping them here would
|
||||
-- delete the data before the copy has a chance to run.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- secret_sources moves to the secret-sources plugin's adopted table at
|
||||
-- activation, after this migration runs. Dropping it here would delete the
|
||||
-- data before the plugin has a chance to rename it.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- webauthn_credentials moves to the webauthn plugin's adopted table at
|
||||
-- activation, and the users TOTP columns are read by the TOTP boot migration
|
||||
-- after this runs. Dropping either here would lose the data first.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- sso_providers moves to the sso plugin's adopted table at activation, and
|
||||
-- its LDAP rows are copied into the ldap plugin by a boot migration after
|
||||
-- this runs. Dropping it here would lose the data first.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- opkssh_tokens moves to the opkssh plugin's adopted table at activation,
|
||||
-- and ssh_data.use_warpgate is copied into the warpgate plugin's host
|
||||
-- settings by a boot migration after this runs. Dropping either here would
|
||||
-- lose the data first.
|
||||
SELECT 1;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- vault_profiles and vault_tokens move to the vault plugin's adopted tables
|
||||
-- at activation, and ssh_data.vault_profile_id is copied into the vault
|
||||
-- plugin's host settings by a boot migration after this runs. Dropping any
|
||||
-- of them here would lose the data first.
|
||||
SELECT 1;
|
||||
@@ -1,4 +0,0 @@
|
||||
-- termix_identities, termix_identity_keys and termix_identity_ca move to the
|
||||
-- termix-identity plugin's adopted tables at activation. Dropping them here
|
||||
-- would lose the data first.
|
||||
SELECT 1;
|
||||
@@ -1,52 +0,0 @@
|
||||
-- The dialect generator now decides varchar or text per table. Columns that
|
||||
-- were varchar(255) only because the same name was a key in another table
|
||||
-- become text, and the timestamps and labels B18's regeneration left as
|
||||
-- varchar(255) on real databases follow. varchar to text keeps every value.
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `name` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `api_keys` MODIFY COLUMN `expires_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `credential_access` MODIFY COLUMN `expires_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `credential_access` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `credential_sidebar_preferences` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `folder_access` MODIFY COLUMN `expires_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `folder_access` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_access` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `host_sidebar_preferences` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `name` text;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `folder` text;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `notification_channels` MODIFY COLUMN `name` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `notification_channels` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `plugin_install_counts` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `plugin_registries` MODIFY COLUMN `name` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `plugin_settings` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `plugin_storage` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `plugins` MODIFY COLUMN `name` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `plugins` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `rbac_known_permissions` MODIFY COLUMN `plugin_id` text;--> statement-breakpoint
|
||||
ALTER TABLE `roles` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `roles` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sessions` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_credential_secrets` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_credential_secrets` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_auth_overrides` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `shared_host_secrets` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `name` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `folder` text;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `name` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `sync_tombstones` MODIFY COLUMN `sync_id` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `trusted_devices` MODIFY COLUMN `expires_at` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ui_preferences` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_external_identities` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `label` text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_open_tabs` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint
|
||||
ALTER TABLE `user_preferences` MODIFY COLUMN `updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP);
|
||||
@@ -1,6 +0,0 @@
|
||||
-- The file manager, tunnels, web endpoint, terminal, tmux monitor, session
|
||||
-- sharing and session recording host columns, and the dead show_*_in_sidebar
|
||||
-- columns, moved to their plugins' host settings. The copies run after
|
||||
-- plugins load, which is after this migration, so a real DROP COLUMN here
|
||||
-- would delete the data first. The columns stay in place, unused, until 3.0.0.
|
||||
SELECT 1;
|
||||
@@ -1,6 +0,0 @@
|
||||
-- dismissed_alerts and notification_channels moved to the alerts plugin. It
|
||||
-- renames the first into its own namespace and copies the second at
|
||||
-- activation, both after this migration, so a real DROP TABLE here would
|
||||
-- delete them first. notification_channels stays in place, unused, until
|
||||
-- 3.0.0.
|
||||
SELECT 1;
|
||||
@@ -1,59 +0,0 @@
|
||||
CREATE TABLE `sync_conflicts` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`entity_type` text NOT NULL,
|
||||
`sync_id` text NOT NULL,
|
||||
`local_row` text NOT NULL,
|
||||
`server_revision` int NOT NULL,
|
||||
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sync_conflicts_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sync_link` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`server_url` text NOT NULL,
|
||||
`server_name` text,
|
||||
`server_version` text,
|
||||
`session_token` text,
|
||||
`custom_headers` text,
|
||||
`basic_auth` text,
|
||||
`allow_invalid_certificate` boolean NOT NULL DEFAULT false,
|
||||
`remote_user_id` text,
|
||||
`remote_username` text,
|
||||
`account` text,
|
||||
`scope` text,
|
||||
`known_types` text,
|
||||
`cursor` int NOT NULL DEFAULT 0,
|
||||
`status` text NOT NULL DEFAULT ('idle'),
|
||||
`last_error` text,
|
||||
`linked_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
`last_sync_at` text,
|
||||
CONSTRAINT `sync_link_id` PRIMARY KEY(`id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `sync_records` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`user_id` varchar(255) NOT NULL,
|
||||
`entity_type` varchar(255) NOT NULL,
|
||||
`sync_id` varchar(255) NOT NULL,
|
||||
`revision` int NOT NULL DEFAULT 0,
|
||||
`seq` int NOT NULL DEFAULT 0,
|
||||
`hash` text,
|
||||
`deleted` boolean NOT NULL DEFAULT false,
|
||||
`error` text,
|
||||
`error_hash` text,
|
||||
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
CONSTRAINT `sync_records_id` PRIMARY KEY(`id`),
|
||||
CONSTRAINT `idx_sync_records_user_entity_sync` UNIQUE(`user_id`,`entity_type`,`sync_id`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `local_only` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_data` ADD `shared_source` text;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_credentials` ADD `shared_source` text;--> statement-breakpoint
|
||||
ALTER TABLE `ssh_folders` ADD `local_only` boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `sync_conflicts` ADD CONSTRAINT `sync_conflicts_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `sync_link` ADD CONSTRAINT `sync_link_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE `sync_records` ADD CONSTRAINT `sync_records_user_id_users_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX `idx_sync_conflicts_user` ON `sync_conflicts` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_sync_records_user_seq` ON `sync_records` (`user_id`,`seq`);
|
||||
@@ -1 +0,0 @@
|
||||
DROP TABLE `sync_tombstones`;
|
||||
@@ -1 +0,0 @@
|
||||
ALTER TABLE `plugin_settings` MODIFY COLUMN `scope` enum('admin','user','host','secret') NOT NULL;
|
||||
Loaded 100 of 1885 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user