Prevent malformed config from being overwritten

This commit is contained in:
Kasra Bigdeli
2026-07-16 17:31:40 -07:00
parent 70dc901d68
commit 198eaa0242
2 changed files with 64 additions and 1 deletions
+22 -1
View File
@@ -38,6 +38,24 @@ const CURRENT_THEME = 'currentTheme'
const DEFAULT_CAPTAIN_ROOT_DOMAIN = 'captain.localhost'
export function validateConfigFile(configPath: string) {
if (!fs.pathExistsSync(configPath)) {
return
}
try {
JSON.parse(fs.readFileSync(configPath, 'utf8'))
} catch (error) {
if (error instanceof SyntaxError) {
throw new Error(
`Cannot start CapRover because ${configPath} contains invalid JSON. Fix the file or restore it from a backup, then restart CapRover.`
)
}
throw error
}
}
const DEFAULT_NGINX_BASE_CONFIG = fs
.readFileSync(__dirname + '/../../template/base-nginx-conf.ejs')
.toString()
@@ -69,11 +87,14 @@ class DataStore {
private projectsDataStore: ProjectsDataStore
constructor(namespace: string) {
const configPath = `${CaptainConstants.captainDataDirectory}/config-${namespace}.json`
validateConfigFile(configPath)
const data = new Configstore(
`captain-store-${namespace}`, // This value seems to be unused
{},
{
configPath: `${CaptainConstants.captainDataDirectory}/config-${namespace}.json`,
configPath,
}
)
+42
View File
@@ -0,0 +1,42 @@
import fs = require('fs-extra')
import os = require('os')
import path = require('path')
import { validateConfigFile } from '../src/datastore/DataStore'
describe('DataStore config validation', () => {
let tempDirectory: string
beforeEach(() => {
tempDirectory = fs.mkdtempSync(
path.join(os.tmpdir(), 'caprover-config-')
)
})
afterEach(() => {
fs.removeSync(tempDirectory)
})
test('does not modify a malformed config file', () => {
const configPath = path.join(tempDirectory, 'config-captain.json')
const malformedConfig = '{"namespace":"captain",}'
fs.writeFileSync(configPath, malformedConfig)
expect(() => validateConfigFile(configPath)).toThrow(
`Cannot start CapRover because ${configPath} contains invalid JSON.`
)
expect(fs.readFileSync(configPath, 'utf8')).toBe(malformedConfig)
})
test('accepts a valid config file', () => {
const configPath = path.join(tempDirectory, 'config-captain.json')
fs.writeJsonSync(configPath, { namespace: 'captain' })
expect(() => validateConfigFile(configPath)).not.toThrow()
})
test('accepts a missing config file on first startup', () => {
const configPath = path.join(tempDirectory, 'config-captain.json')
expect(() => validateConfigFile(configPath)).not.toThrow()
})
})