feat: Companion agent download in ServerView + Gitea CI pipeline fix
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
Frontend: - Add Companion Agent card to ServerView (status, download links, setup instructions) - Shows agent connection status, last heartbeat, license key for copy - Download buttons for Linux/Windows amd64 from Gitea releases CI/CD: - Fix build-companion.yml: replace actions/github-script with Gitea API curl - Inject version from git tag via ldflags (-X main.version) - Add VERSION variable to Makefile with ldflags injection - Change main.go version from const to var for ldflags compatibility Deployment: - Add systemd service file (deployment/corrosion-companion.service) - Add .gitignore for bin/ (binaries should come from CI, not repo) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,13 +26,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd companion-agent
|
cd companion-agent
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o bin/corrosion-companion-linux-amd64 ./cmd/agent
|
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${{ steps.version.outputs.VERSION }}" -o bin/corrosion-companion-linux-amd64 ./cmd/agent
|
||||||
chmod +x bin/corrosion-companion-linux-amd64
|
chmod +x bin/corrosion-companion-linux-amd64
|
||||||
|
|
||||||
- name: Build Windows AMD64
|
- name: Build Windows AMD64
|
||||||
run: |
|
run: |
|
||||||
cd companion-agent
|
cd companion-agent
|
||||||
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o bin/corrosion-companion-windows-amd64.exe ./cmd/agent
|
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.version=${{ steps.version.outputs.VERSION }}" -o bin/corrosion-companion-windows-amd64.exe ./cmd/agent
|
||||||
|
|
||||||
- name: Generate checksums
|
- name: Generate checksums
|
||||||
run: |
|
run: |
|
||||||
@@ -42,85 +42,49 @@ jobs:
|
|||||||
cat checksums.txt
|
cat checksums.txt
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: actions/github-script@v6
|
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.version.outputs.VERSION }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
with:
|
run: |
|
||||||
script: |
|
VERSION=${{ steps.version.outputs.VERSION }}
|
||||||
const fs = require('fs').promises;
|
REPO="vantzs/corrosion-admin-panel"
|
||||||
const path = require('path');
|
API_URL="https://git.corrosionmgmt.com/api/v1"
|
||||||
|
|
||||||
// Create release
|
# Create release
|
||||||
const release = await github.rest.repos.createRelease({
|
RELEASE_ID=$(curl -s -X POST \
|
||||||
owner: context.repo.owner,
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
repo: context.repo.repo,
|
-H "Content-Type: application/json" \
|
||||||
tag_name: process.env.VERSION,
|
-d "{\"tag_name\": \"${VERSION}\", \"name\": \"Companion Agent ${VERSION}\", \"body\": \"Companion Agent release ${VERSION}\", \"draft\": false, \"prerelease\": false}" \
|
||||||
name: `Companion Agent ${process.env.VERSION}`,
|
"${API_URL}/repos/${REPO}/releases" | jq -r '.id')
|
||||||
body: `## Corrosion Companion Agent ${process.env.VERSION}
|
|
||||||
|
|
||||||
### Installation
|
# Upload Linux binary
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @companion-agent/bin/corrosion-companion-linux-amd64 \
|
||||||
|
"${API_URL}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=corrosion-companion-linux-amd64"
|
||||||
|
|
||||||
**Linux:**
|
# Upload Windows binary
|
||||||
\`\`\`bash
|
curl -s -X POST \
|
||||||
wget https://git.corrosionmgmt.com/vantzs/corrosion-admin-panel/releases/download/${process.env.VERSION}/corrosion-companion-linux-amd64
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
chmod +x corrosion-companion-linux-amd64
|
-H "Content-Type: application/octet-stream" \
|
||||||
sudo mv corrosion-companion-linux-amd64 /usr/local/bin/corrosion-companion
|
--data-binary @companion-agent/bin/corrosion-companion-windows-amd64.exe \
|
||||||
\`\`\`
|
"${API_URL}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=corrosion-companion-windows-amd64.exe"
|
||||||
|
|
||||||
**Windows:**
|
# Upload checksums
|
||||||
Download \`corrosion-companion-windows-amd64.exe\` and run as administrator.
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
### Checksums
|
-H "Content-Type: application/octet-stream" \
|
||||||
See \`checksums.txt\` for SHA256 verification.
|
--data-binary @companion-agent/bin/checksums.txt \
|
||||||
|
"${API_URL}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=checksums.txt"
|
||||||
### What's New
|
|
||||||
- Built from commit: ${context.sha.substring(0, 7)}
|
|
||||||
- Go version: 1.21
|
|
||||||
- Platforms: Linux AMD64, Windows AMD64
|
|
||||||
`,
|
|
||||||
draft: false,
|
|
||||||
prerelease: false
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Created release: ${release.data.html_url}`);
|
|
||||||
|
|
||||||
// Upload Linux binary
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
release_id: release.data.id,
|
|
||||||
name: 'corrosion-companion-linux-amd64',
|
|
||||||
data: await fs.readFile('companion-agent/bin/corrosion-companion-linux-amd64')
|
|
||||||
});
|
|
||||||
|
|
||||||
// Upload Windows binary
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
release_id: release.data.id,
|
|
||||||
name: 'corrosion-companion-windows-amd64.exe',
|
|
||||||
data: await fs.readFile('companion-agent/bin/corrosion-companion-windows-amd64.exe')
|
|
||||||
});
|
|
||||||
|
|
||||||
// Upload checksums
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
release_id: release.data.id,
|
|
||||||
name: 'checksums.txt',
|
|
||||||
data: await fs.readFile('companion-agent/bin/checksums.txt')
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Uploaded all release assets');
|
|
||||||
|
|
||||||
- name: Build Summary
|
- name: Build Summary
|
||||||
run: |
|
run: |
|
||||||
echo "## 🚀 Companion Agent Build Complete" >> $GITHUB_STEP_SUMMARY
|
echo "## Companion Agent Build Complete" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "**Version:** ${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
|
echo "**Version:** ${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "**Commit:** ${GITHUB_SHA:0:7}" >> $GITHUB_STEP_SUMMARY
|
echo "**Commit:** ${GITHUB_SHA:0:7}" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "### Built Artifacts:" >> $GITHUB_STEP_SUMMARY
|
echo "### Built Artifacts:" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- ✅ Linux AMD64 ($(stat -f%z companion-agent/bin/corrosion-companion-linux-amd64 2>/dev/null || stat -c%s companion-agent/bin/corrosion-companion-linux-amd64) bytes)" >> $GITHUB_STEP_SUMMARY
|
echo "- Linux AMD64 ($(stat -c%s companion-agent/bin/corrosion-companion-linux-amd64) bytes)" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- ✅ Windows AMD64 ($(stat -f%z companion-agent/bin/corrosion-companion-windows-amd64.exe 2>/dev/null || stat -c%s companion-agent/bin/corrosion-companion-windows-amd64.exe) bytes)" >> $GITHUB_STEP_SUMMARY
|
echo "- Windows AMD64 ($(stat -c%s companion-agent/bin/corrosion-companion-windows-amd64.exe) bytes)" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "- ✅ SHA256 checksums" >> $GITHUB_STEP_SUMMARY
|
echo "- SHA256 checksums" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|||||||
1
companion-agent/.gitignore
vendored
Normal file
1
companion-agent/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bin/
|
||||||
@@ -16,8 +16,11 @@ GOTEST=$(GOCMD) test
|
|||||||
GOGET=$(GOCMD) get
|
GOGET=$(GOCMD) get
|
||||||
GOMOD=$(GOCMD) mod
|
GOMOD=$(GOCMD) mod
|
||||||
|
|
||||||
|
# Version (overridable via: make build-linux VERSION=v1.2.3)
|
||||||
|
VERSION ?= dev
|
||||||
|
|
||||||
# Build flags
|
# Build flags
|
||||||
LDFLAGS=-ldflags "-s -w"
|
LDFLAGS = -ldflags "-s -w -X main.version=$(VERSION)"
|
||||||
|
|
||||||
all: clean build
|
all: clean build
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ type Config struct {
|
|||||||
LogLevel string `envconfig:"LOG_LEVEL" default:"info"`
|
LogLevel string `envconfig:"LOG_LEVEL" default:"info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const version = "1.0.0"
|
var version = "dev"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
|||||||
28
companion-agent/deployment/corrosion-companion.service
Normal file
28
companion-agent/deployment/corrosion-companion.service
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Corrosion Companion Agent
|
||||||
|
Documentation=https://corrosionmgmt.com
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=rust
|
||||||
|
Group=rust
|
||||||
|
WorkingDirectory=/opt/corrosion
|
||||||
|
ExecStart=/opt/corrosion/corrosion-companion-linux-amd64
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
StartLimitInterval=60
|
||||||
|
StartLimitBurst=3
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
EnvironmentFile=/opt/corrosion/.env
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ReadWritePaths=/opt/corrosion /home/rust
|
||||||
|
ProtectHome=read-only
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useServerStore } from '@/stores/server'
|
import { useServerStore } from '@/stores/server'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
import {
|
import {
|
||||||
Server,
|
Server,
|
||||||
Wifi,
|
Wifi,
|
||||||
@@ -10,13 +11,62 @@ import {
|
|||||||
RotateCcw,
|
RotateCcw,
|
||||||
Save,
|
Save,
|
||||||
Loader2,
|
Loader2,
|
||||||
|
Download,
|
||||||
|
Terminal,
|
||||||
|
Monitor,
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
|
|
||||||
const server = useServerStore()
|
const server = useServerStore()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
|
||||||
const editMode = ref(false)
|
const editMode = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const actionLoading = ref<string | null>(null)
|
const actionLoading = ref<string | null>(null)
|
||||||
|
const copied = ref(false)
|
||||||
|
|
||||||
|
const isAgentConnected = computed(() =>
|
||||||
|
server.connection?.connection_type === 'bare_metal' &&
|
||||||
|
server.connection?.connection_status === 'connected'
|
||||||
|
)
|
||||||
|
|
||||||
|
const agentLastSeen = computed(() => {
|
||||||
|
const ts = server.connection?.companion_last_seen
|
||||||
|
if (!ts) return null
|
||||||
|
return new Date(ts)
|
||||||
|
})
|
||||||
|
|
||||||
|
const agentLastSeenLabel = computed(() => {
|
||||||
|
const d = agentLastSeen.value
|
||||||
|
if (!d) return 'Never'
|
||||||
|
const diff = Math.floor((Date.now() - d.getTime()) / 1000)
|
||||||
|
if (diff < 60) return `${diff}s ago`
|
||||||
|
if (diff < 3600) return `${Math.floor(diff / 60)}m ago`
|
||||||
|
if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`
|
||||||
|
return d.toLocaleDateString()
|
||||||
|
})
|
||||||
|
|
||||||
|
const licenseKey = computed(() => auth.license?.license_key || 'YOUR-LICENSE-KEY')
|
||||||
|
|
||||||
|
const linuxCommands = computed(() => `# Download the agent
|
||||||
|
curl -LO https://git.corrosionmgmt.com/vantzs/corrosion-admin-panel/releases/latest/download/corrosion-companion-linux-amd64
|
||||||
|
chmod +x corrosion-companion-linux-amd64
|
||||||
|
|
||||||
|
# Start with your license key
|
||||||
|
export LICENSE_ID="${licenseKey.value}"
|
||||||
|
export NATS_URL="nats://nats.corrosionmgmt.com:4222"
|
||||||
|
export NATS_TOKEN="<your-nats-token>"
|
||||||
|
export GAME_SERVER_PATH="/path/to/RustDedicated"
|
||||||
|
./corrosion-companion-linux-amd64`)
|
||||||
|
|
||||||
|
async function copyCommands() {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(linuxCommands.value)
|
||||||
|
copied.value = true
|
||||||
|
setTimeout(() => { copied.value = false }, 2000)
|
||||||
|
} catch {
|
||||||
|
// Clipboard API unavailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
server_name: '',
|
server_name: '',
|
||||||
@@ -148,6 +198,101 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Companion Agent -->
|
||||||
|
<div class="bg-neutral-900 border border-neutral-800 rounded-lg p-5">
|
||||||
|
<div class="flex items-center gap-2 mb-5">
|
||||||
|
<Monitor class="w-4 h-4 text-oxide-400" />
|
||||||
|
<h2 class="text-sm font-medium text-neutral-400 uppercase tracking-wider">Companion Agent</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Agent Status -->
|
||||||
|
<div class="grid grid-cols-2 lg:grid-cols-3 gap-6 mb-6">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-neutral-500 mb-1">Agent Status</p>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
class="w-2 h-2 rounded-full"
|
||||||
|
:class="isAgentConnected ? 'bg-green-400' : 'bg-neutral-600'"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="text-sm font-medium"
|
||||||
|
:class="isAgentConnected ? 'text-green-400' : 'text-neutral-400'"
|
||||||
|
>
|
||||||
|
{{ isAgentConnected ? 'Active' : 'Inactive' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-neutral-500 mb-1">Connection Type</p>
|
||||||
|
<p class="text-sm font-medium text-neutral-100 uppercase">
|
||||||
|
{{ server.connection?.connection_type || '\u2014' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-neutral-500 mb-1">Last Heartbeat</p>
|
||||||
|
<p class="text-sm font-medium" :class="agentLastSeen ? 'text-neutral-200' : 'text-neutral-500'">
|
||||||
|
{{ agentLastSeenLabel }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Download Section -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
<Download class="w-3.5 h-3.5 text-neutral-500" />
|
||||||
|
<p class="text-xs font-medium text-neutral-400 uppercase tracking-wider">Download Companion Agent</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap gap-3">
|
||||||
|
<a
|
||||||
|
href="https://git.corrosionmgmt.com/vantzs/corrosion-admin-panel/releases/latest/download/corrosion-companion-linux-amd64"
|
||||||
|
download="corrosion-companion-linux-amd64"
|
||||||
|
class="flex items-center gap-2 px-4 py-2.5 bg-neutral-800 hover:bg-neutral-700 text-neutral-200 border border-neutral-700 hover:border-neutral-600 rounded-lg text-sm font-medium transition-colors"
|
||||||
|
>
|
||||||
|
<Download class="w-4 h-4 text-oxide-400" />
|
||||||
|
Linux (amd64)
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://git.corrosionmgmt.com/vantzs/corrosion-admin-panel/releases/latest/download/corrosion-companion-windows-amd64.exe"
|
||||||
|
download="corrosion-companion-windows-amd64.exe"
|
||||||
|
class="flex items-center gap-2 px-4 py-2.5 bg-neutral-800 hover:bg-neutral-700 text-neutral-200 border border-neutral-700 hover:border-neutral-600 rounded-lg text-sm font-medium transition-colors"
|
||||||
|
>
|
||||||
|
<Download class="w-4 h-4 text-oxide-400" />
|
||||||
|
Windows (amd64)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Setup Section -->
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between mb-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Terminal class="w-3.5 h-3.5 text-neutral-500" />
|
||||||
|
<p class="text-xs font-medium text-neutral-400 uppercase tracking-wider">Quick Setup (Linux)</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
@click="copyCommands"
|
||||||
|
class="flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-md transition-colors"
|
||||||
|
:class="copied
|
||||||
|
? 'bg-green-600/20 text-green-400 border border-green-600/30'
|
||||||
|
: 'bg-neutral-800 hover:bg-neutral-700 text-neutral-400 hover:text-neutral-200 border border-neutral-700'"
|
||||||
|
>
|
||||||
|
{{ copied ? 'Copied!' : 'Copy' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="bg-black/50 border border-neutral-800 rounded-lg p-4 font-mono text-sm text-neutral-300 overflow-x-auto">
|
||||||
|
<p class="text-neutral-500"># Download the agent</p>
|
||||||
|
<p>curl -LO https://git.corrosionmgmt.com/vantzs/corrosion-admin-panel/releases/latest/download/corrosion-companion-linux-amd64</p>
|
||||||
|
<p>chmod +x corrosion-companion-linux-amd64</p>
|
||||||
|
<p class="mt-3 text-neutral-500"># Start with your license key</p>
|
||||||
|
<p>export LICENSE_ID=<span class="text-oxide-400">"{{ licenseKey }}"</span></p>
|
||||||
|
<p>export NATS_URL=<span class="text-oxide-400">"nats://nats.corrosionmgmt.com:4222"</span></p>
|
||||||
|
<p>export NATS_TOKEN=<span class="text-neutral-500">"<your-nats-token>"</span></p>
|
||||||
|
<p>export GAME_SERVER_PATH=<span class="text-neutral-500">"/path/to/RustDedicated"</span></p>
|
||||||
|
<p>./corrosion-companion-linux-amd64</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Configuration -->
|
<!-- Configuration -->
|
||||||
<div class="bg-neutral-900 border border-neutral-800 rounded-lg p-5">
|
<div class="bg-neutral-900 border border-neutral-800 rounded-lg p-5">
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user