feat: add ! kubectl command to terminal + restrict RBAC (no secrets/configmaps)
Build & Push Portfolio Image / build-push (push) Successful in 3m29s
Build & Push Portfolio Image / build-push (push) Successful in 3m29s
This commit is contained in:
@@ -35,7 +35,9 @@ function useTheme() {
|
||||
}
|
||||
|
||||
const commands: Record<string, string> = {
|
||||
help: `QUESTIONS TO EXPLORE:
|
||||
help: `COMMANDS: help, /clear, ! kubectl
|
||||
|
||||
QUESTIONS TO EXPLORE:
|
||||
|
||||
Homelab & Infrastructure
|
||||
• Did you build Kubernetes from scratch? How hard?
|
||||
@@ -173,6 +175,53 @@ export function InteractiveTerminal() {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle ! kubectl commands
|
||||
if (trimmed.startsWith('!')) {
|
||||
const kubectlCmd = trimmed.slice(1).trim()
|
||||
if (!kubectlCmd.startsWith('kubectl ')) {
|
||||
setHistory(prev => [...prev, { cmd: trimmed, output: 'Error: only kubectl commands supported (e.g. ! kubectl get pods)' }])
|
||||
setInput('')
|
||||
return
|
||||
}
|
||||
|
||||
setIsLoading(true)
|
||||
setInput('')
|
||||
setHistory(prev => [...prev, { cmd: trimmed, output: '', isStreaming: true }])
|
||||
const entryIndex = history.length
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/kubectl', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ command: kubectlCmd }),
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
setHistory(prev => {
|
||||
const updated = [...prev]
|
||||
const entry = updated[entryIndex]
|
||||
if (entry) {
|
||||
entry.output = data.error || data.output || 'No output'
|
||||
entry.isStreaming = false
|
||||
}
|
||||
return updated
|
||||
})
|
||||
} catch (err) {
|
||||
setHistory(prev => {
|
||||
const updated = [...prev]
|
||||
const entry = updated[entryIndex]
|
||||
if (entry) {
|
||||
entry.output = `Error: ${err instanceof Error ? err.message : 'Request failed'}`
|
||||
entry.isStreaming = false
|
||||
}
|
||||
return updated
|
||||
})
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Check for built-in commands
|
||||
if (commands[lowerCmd]) {
|
||||
setHistory(prev => [...prev, { cmd: trimmed, output: commands[lowerCmd] }])
|
||||
|
||||
Reference in New Issue
Block a user