From 092661c7ebb28e1fb24bada803de9b1284c425f0 Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 30 Oct 2025 21:10:58 +0000 Subject: [PATCH 01/10] doc: Better default config that includes security examples and more doc links --- config.yaml | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/config.yaml b/config.yaml index 17599a4..ca2da10 100644 --- a/config.yaml +++ b/config.yaml @@ -5,20 +5,16 @@ # Listen on all addresses available, port 1337 listenAddressSingleHTTPFrontend: 0.0.0.0:1337 -bannerMessage: "This is an early alpha version of OliveTin 3000. Many thanks are broken, many things will change." -bannerCss: "background-color: #b2e4b2; color: black; font-size: small; text-align: center; padding: .6em; border-radius: 0.5em;" - -insecureAllowDumpSos: true -insecureAllowDumpVars: true - # Choose from INFO (default), WARN and DEBUG +# Docs: https://docs.olivetin.app/advanced_configuration/logs.html logLevel: "INFO" -# Checking for updates https://docs.olivetin.app/reference/updateChecks.html +# Docs: https://docs.olivetin.app/reference/updateChecks.html checkForUpdates: false -authLocalUsers: - enabled: true +# Docs: https://docs.olivetin.app/security/acl.html +defaultPolicy: + showDiagnostics: false # Actions are commands that are executed by OliveTin, and normally show up as # buttons on the WebUI. @@ -322,3 +318,34 @@ dashboards: - title: 'Start {{ .CurrentEntity.Names }}' - title: 'Stop {{ .CurrentEntity.Names }}' + +# This form of auth is the simplest to setup - just define users and passwords +# in the config. +# Docs: https://docs.olivetin.app/security/local.html +authLocalUsers: + enabled: true +# users: +# - username: alice +# usergroup: admins +# password: "$argon2id$v=19$m=65536,t=4,p=6$LnNW4sw+jZfa5Ex3YjfuHQ$vl8pjUJhxNmBxScV4lI3cgAZPkNB1rSrnX6ibgoAP8k" + +# OliveTin uses access control lists to match up policy and permissions to users. +# Policies affect the whole app (eg: ability to view the log list). +# Permissions affect actions (eg: ability to view a specific log). +# Docs: https://docs.olivetin.app/security/acl.html +accessControlLists: + - name: admin_acl + matchUsergroups: ["admins"] + policy: + showDiagnostics: true + permissions: + view: true + exec: true + logs: true + +# Docs: https://docs.olivetin.app/security/acl.html +defaultPermissions: + view: true + exec: true + logs: true + From 0bf313a3f722ba35036c9958f5b469dc6dca16d3 Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 30 Oct 2025 21:14:49 +0000 Subject: [PATCH 02/10] doc: Move defaultPolicy to the end in the config --- config.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/config.yaml b/config.yaml index ca2da10..e655b36 100644 --- a/config.yaml +++ b/config.yaml @@ -9,13 +9,6 @@ listenAddressSingleHTTPFrontend: 0.0.0.0:1337 # Docs: https://docs.olivetin.app/advanced_configuration/logs.html logLevel: "INFO" -# Docs: https://docs.olivetin.app/reference/updateChecks.html -checkForUpdates: false - -# Docs: https://docs.olivetin.app/security/acl.html -defaultPolicy: - showDiagnostics: false - # Actions are commands that are executed by OliveTin, and normally show up as # buttons on the WebUI. # @@ -349,3 +342,7 @@ defaultPermissions: exec: true logs: true +# Docs: https://docs.olivetin.app/security/acl.html +defaultPolicy: + showDiagnostics: false + From f1250f9caf0b4378266feb88d50894adcb2009ab Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 30 Oct 2025 21:24:13 +0000 Subject: [PATCH 03/10] doc: Add more security examples to default config --- config.yaml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index e655b36..a04d060 100644 --- a/config.yaml +++ b/config.yaml @@ -312,15 +312,29 @@ dashboards: - title: 'Start {{ .CurrentEntity.Names }}' - title: 'Stop {{ .CurrentEntity.Names }}' + +# Security - Authentication + +# This setting effectively enables or disables guests. +# If set to "true", then users will have to login to do anything. +authRequireGuestsToLogin: false + # This form of auth is the simplest to setup - just define users and passwords -# in the config. +# in the config. OliveTin also supports header-based auth, OAuth2, +# and JWT authentication which are documented separately. +# # Docs: https://docs.olivetin.app/security/local.html +# +# How to get a hashed password: +# Docs: https://docs.olivetin.app/security/local.html#_get_a_argon2id_hashed_password authLocalUsers: enabled: true # users: # - username: alice # usergroup: admins -# password: "$argon2id$v=19$m=65536,t=4,p=6$LnNW4sw+jZfa5Ex3YjfuHQ$vl8pjUJhxNmBxScV4lI3cgAZPkNB1rSrnX6ibgoAP8k" +# password: "$argon2id$v=19$m=65536,t=4,p=2$puyxA0s555TSFx7hnFLCXA$PyhLGpZtvpMMvc2DgMWkM8OJMKO55euwV5gm//1iwx4" + +# Security - Access Control Lists # OliveTin uses access control lists to match up policy and permissions to users. # Policies affect the whole app (eg: ability to view the log list). From 6782156a588e0a0a158a40a26109f3f8537a7ce8 Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 30 Oct 2025 21:33:10 +0000 Subject: [PATCH 04/10] doc: Add date id --- config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config.yaml b/config.yaml index a04d060..f159bae 100644 --- a/config.yaml +++ b/config.yaml @@ -44,6 +44,7 @@ actions: # You can also rate-limit actions too. - title: date shell: date + id: date timeout: 6 icon: clock popupOnStart: execution-button From 2b1f9a924751b242ed80f5895d55691e60763b1f Mon Sep 17 00:00:00 2001 From: jamesread Date: Fri, 31 Oct 2025 09:18:45 +0000 Subject: [PATCH 05/10] doc: Better layout of default config security section --- config.yaml | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/config.yaml b/config.yaml index f159bae..ee4c6ba 100644 --- a/config.yaml +++ b/config.yaml @@ -335,11 +335,22 @@ authLocalUsers: # usergroup: admins # password: "$argon2id$v=19$m=65536,t=4,p=2$puyxA0s555TSFx7hnFLCXA$PyhLGpZtvpMMvc2DgMWkM8OJMKO55euwV5gm//1iwx4" -# Security - Access Control Lists +# Security - Access Control + +# Policies affect the whole app (eg: ability to view the log list). +# Docs: https://docs.olivetin.app/security/acl.html +defaultPolicy: + showDiagnostics: true + showLogList: true + +# Permissions affect actions (eg: ability to view a specific log). +# Docs: https://docs.olivetin.app/security/acl.html +defaultPermissions: + view: true + exec: true + logs: true # OliveTin uses access control lists to match up policy and permissions to users. -# Policies affect the whole app (eg: ability to view the log list). -# Permissions affect actions (eg: ability to view a specific log). # Docs: https://docs.olivetin.app/security/acl.html accessControlLists: - name: admin_acl @@ -351,13 +362,5 @@ accessControlLists: exec: true logs: true -# Docs: https://docs.olivetin.app/security/acl.html -defaultPermissions: - view: true - exec: true - logs: true - -# Docs: https://docs.olivetin.app/security/acl.html -defaultPolicy: - showDiagnostics: false - +# OliveTin contains many more configuration options not in this default config. +# Check out docs.olivetin.app for a setting if you feel like you're missing something. From d3cd876eec1b8e0a4cfb8e857ede452230b8b2d5 Mon Sep 17 00:00:00 2001 From: jamesread Date: Fri, 31 Oct 2025 09:26:40 +0000 Subject: [PATCH 06/10] doc: Added API docs generation tool for 3k --- proto/buf.gen.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/proto/buf.gen.yaml b/proto/buf.gen.yaml index 18c2b3a..29b577b 100644 --- a/proto/buf.gen.yaml +++ b/proto/buf.gen.yaml @@ -11,8 +11,7 @@ plugins: - remote: buf.build/bufbuild/es out: ../frontend/resources/scripts/gen/ -# - name: swagger -# out: reports/swagger - +# - local: ["go", "run", "github.com/sudorandom/protoc-gen-connect-openapi@latest"] +# out: gen # - local: protoc-gen-openapiv2 # out: reports/openapiv2 From 294e33d1107149e04b438b1d6f22dbb99fa88d36 Mon Sep 17 00:00:00 2001 From: jamesread Date: Tue, 4 Nov 2025 23:03:45 +0000 Subject: [PATCH 07/10] fix: #686 - concurrent map read and write --- service/internal/entities/storage.go | 6 ++++++ service/internal/entities/templates.go | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/service/internal/entities/storage.go b/service/internal/entities/storage.go index b94ddf5..5bed05c 100644 --- a/service/internal/entities/storage.go +++ b/service/internal/entities/storage.go @@ -60,10 +60,16 @@ func GetAll() *variableBase { } func GetEntities() entitiesByClass { + rwmutex.RLock() + defer rwmutex.RUnlock() + return contents.Entities } func GetEntityInstances(entityName string) entityInstancesByKey { + rwmutex.RLock() + defer rwmutex.RUnlock() + if entities, ok := contents.Entities[entityName]; ok { return entities } diff --git a/service/internal/entities/templates.go b/service/internal/entities/templates.go index 46b5bff..ccb67f0 100644 --- a/service/internal/entities/templates.go +++ b/service/internal/entities/templates.go @@ -91,7 +91,7 @@ func ParseTemplateWithArgs(source string, ent *Entity, args map[string]string) s } templateVariables := &variableBase{ - OliveTin: contents.OliveTin, + OliveTin: GetAll().OliveTin, Arguments: args, CurrentEntity: entdata, } @@ -126,5 +126,8 @@ func ParseTemplateBoolWith(source string, ent *Entity) bool { } func ClearEntities(entityType string) { + rwmutex.Lock() + defer rwmutex.Unlock() + delete(contents.Entities, entityType) } From 2b24daa6d0f9e226ce71569e474fa72fb98600e8 Mon Sep 17 00:00:00 2001 From: jamesread Date: Tue, 4 Nov 2025 23:18:41 +0000 Subject: [PATCH 08/10] fix: Address concurrency issue in entities storage --- service/internal/entities/storage.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/service/internal/entities/storage.go b/service/internal/entities/storage.go index 5bed05c..55a3e36 100644 --- a/service/internal/entities/storage.go +++ b/service/internal/entities/storage.go @@ -61,9 +61,19 @@ func GetAll() *variableBase { func GetEntities() entitiesByClass { rwmutex.RLock() - defer rwmutex.RUnlock() - return contents.Entities + copiedEntities := make(entitiesByClass, len(contents.Entities)) + for entityName, entityInstances := range contents.Entities { + copiedInstances := make(entityInstancesByKey, len(entityInstances)) + for key, entity := range entityInstances { + copiedInstances[key] = entity + } + copiedEntities[entityName] = copiedInstances + } + + rwmutex.RUnlock() + + return copiedEntities } func GetEntityInstances(entityName string) entityInstancesByKey { From 055472902d9d6b71853ec4502e5a61a71f56116a Mon Sep 17 00:00:00 2001 From: jamesread Date: Tue, 4 Nov 2025 23:30:14 +0000 Subject: [PATCH 09/10] fix: #686 - concurrent map read and write - in entity instances --- service/internal/entities/storage.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/service/internal/entities/storage.go b/service/internal/entities/storage.go index 55a3e36..0ac35b3 100644 --- a/service/internal/entities/storage.go +++ b/service/internal/entities/storage.go @@ -63,8 +63,10 @@ func GetEntities() entitiesByClass { rwmutex.RLock() copiedEntities := make(entitiesByClass, len(contents.Entities)) + for entityName, entityInstances := range contents.Entities { copiedInstances := make(entityInstancesByKey, len(entityInstances)) + for key, entity := range entityInstances { copiedInstances[key] = entity } @@ -81,10 +83,15 @@ func GetEntityInstances(entityName string) entityInstancesByKey { defer rwmutex.RUnlock() if entities, ok := contents.Entities[entityName]; ok { - return entities + copiedInstances := make(entityInstancesByKey, len(entities)) + + for key, entity := range entities { + copiedInstances[key] = entity + } + return copiedInstances } - return nil + return make(entityInstancesByKey, 0) } func AddEntity(entityName string, entityKey string, data any) { From 28c813762f56541f9fc845710483b5f6b96da10c Mon Sep 17 00:00:00 2001 From: jamesread Date: Thu, 6 Nov 2025 00:38:56 +0000 Subject: [PATCH 10/10] fix: #685 - show navigation (and picocrank upgrade) --- .gitignore | 2 ++ frontend/package-lock.json | 8 +++---- frontend/package.json | 2 +- frontend/resources/vue/App.vue | 40 +++++++++++++++++++--------------- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 561630f..f2d12e3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ webui/ server.log OliveTin integration-tests/configs/authRequireGuestsToLogin/sessions.yaml +webui +webui.dev diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 48f4f14..a8a3291 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "iconify-icon": "^3.0.2", - "picocrank": "^1.6.4", + "picocrank": "^1.8.0", "unplugin-vue-components": "^30.0.0", "vite": "^7.1.12", "vue-router": "^4.6.3" @@ -2362,9 +2362,9 @@ "license": "ISC" }, "node_modules/picocrank": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/picocrank/-/picocrank-1.6.4.tgz", - "integrity": "sha512-zD1wnkoUDAXZOUs9zKqS4rqz9mljeqFwM7QWx4ykXJsmH6iOLAIKh2AVlxa384oeXJXIWM9VLiySEnhQZmQmjA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/picocrank/-/picocrank-1.8.0.tgz", + "integrity": "sha512-YPGmXvw7vvjIcgrAe3io87kZDM+NUa+aiEYxk8CVqBzgI4koXeF+2VEGPHBwknZBBEbJfXsSdnxVwXrLKpWKfw==", "license": "ISC", "dependencies": { "@hugeicons/core-free-icons": "^1.0.16", diff --git a/frontend/package.json b/frontend/package.json index 357ee66..6e86726 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,7 +30,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "iconify-icon": "^3.0.2", - "picocrank": "^1.6.4", + "picocrank": "^1.8.0", "unplugin-vue-components": "^30.0.0", "vite": "^7.1.12", "vue-router": "^4.6.3" diff --git a/frontend/resources/vue/App.vue b/frontend/resources/vue/App.vue index 2c18e31..8e552bf 100644 --- a/frontend/resources/vue/App.vue +++ b/frontend/resources/vue/App.vue @@ -1,5 +1,5 @@