Merge branch 'next' into dependabot/npm_and_yarn/frontend/minimatch-3.1.5

This commit is contained in:
James Read 2026-03-01 19:36:51 -05:00 committed by GitHub
commit e8e62d22f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 233 additions and 61 deletions

View File

@ -10,6 +10,7 @@
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5050/badge)](https://bestpractices.coreinfrastructure.org/projects/5050)
[![Go Report Card](https://goreportcard.com/badge/github.com/Olivetin/OliveTin)](https://goreportcard.com/report/github.com/OliveTin/OliveTin)
[![AI Autonomy Level](https://img.shields.io/badge/AI%20Autonomy-Level%201%20of%205%20(assistance--only)-blue)](https://blog.jread.com/posts/ai-levels-of-autonomy-in-software-engineering/)
[OliveTin 2k to 3k upgrade guide](https://docs.olivetin.app/upgrade/2k3k.html)
</div>

View File

@ -1,5 +1,6 @@
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import { WebLinksAddon } from '@xterm/addon-web-links'
import { Mutex } from './Mutex.js'
/**
@ -18,13 +19,24 @@ export class OutputTerminal {
constructor (executionTrackingId) {
this.executionTrackingId = executionTrackingId
this.writeMutex = new Mutex()
const linkHandler = {
activate (event, text, _range) {
event.preventDefault()
window.open(text, '_blank')
}
}
this.terminal = new Terminal({
convertEol: true
convertEol: true,
linkHandler
})
const fitAddon = new FitAddon()
this.terminal.loadAddon(fitAddon)
this.terminal.fit = fitAddon
this.terminal.loadAddon(new WebLinksAddon((event, uri) => linkHandler.activate(event, uri)))
this.linkHandlerConfigured = true
}
async write (out, then) {

View File

@ -15,6 +15,7 @@
"@hugeicons/vue": "^1.0.4",
"@vitejs/plugin-vue": "^6.0.4",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^6.0.0",
"iconify-icon": "^3.0.2",
"picocrank": "^1.14.0",
@ -1570,6 +1571,12 @@
"integrity": "sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g==",
"license": "MIT"
},
"node_modules/@xterm/addon-web-links": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.12.0.tgz",
"integrity": "sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw==",
"license": "MIT"
},
"node_modules/@xterm/xterm": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.0.0.tgz",

View File

@ -28,13 +28,14 @@
"@hugeicons/vue": "^1.0.4",
"@vitejs/plugin-vue": "^6.0.4",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^6.0.0",
"iconify-icon": "^3.0.2",
"picocrank": "^1.14.0",
"standard": "^17.1.2",
"unplugin-vue-components": "^31.0.0",
"vite": "^7.3.1",
"vue": "^3.5.29",
"vue": "^3.5.29",
"vue-i18n": "^11.2.8",
"vue-router": "^5.0.3"
}

View File

@ -210,6 +210,11 @@ export declare type EffectivePolicy = Message<"olivetin.api.v1.EffectivePolicy">
* @generated from field: bool show_log_list = 2;
*/
showLogList: boolean;
/**
* @generated from field: bool show_version_number = 3;
*/
showVersionNumber: boolean;
};
/**
@ -1853,4 +1858,3 @@ export declare const OliveTinApiService: GenService<{
output: typeof EntitySchema;
},
}>;

File diff suppressed because one or more lines are too long

View File

@ -31,7 +31,7 @@
<footer title="footer" v-if="showFooter">
<p>
<img title="application icon" :src="logoUrl" alt="OliveTin logo" style="height: 1em;" class="logo" />
OliveTin {{ currentVersion }}
OliveTin <span v-if="showVersionNumber">{{ currentVersion }}</span>
</p>
<p>
<span>
@ -52,7 +52,7 @@
<span>{{ t('connected') }}</span>
</p>
<p>
<p v-if="showVersionNumber">
<a id="available-version" href="http://olivetin.app" target="_blank" hidden>?</a>
</p>
</footer>
@ -126,6 +126,7 @@ const showFooter = ref(true)
const showNavigation = ref(true)
const showLogs = ref(true)
const showDiagnostics = ref(true)
const showVersionNumber = ref(true)
const showLoginLink = ref(true)
const sectionNavigationStyle = ref('sidebar')
@ -223,6 +224,7 @@ function updateHeaderFromInit() {
showNavigation.value = window.initResponse.showNavigation
showLogs.value = window.initResponse.showLogList
showDiagnostics.value = window.initResponse.showDiagnostics
showVersionNumber.value = window.initResponse.effectivePolicy?.showVersionNumber ?? true
sectionNavigationStyle.value = window.initResponse.sectionNavigationStyle || 'sidebar'
availableThemes.value = window.initResponse.availableThemes || []

View File

@ -162,7 +162,10 @@ async function generateBrowserInfo() {
userAgentData: userAgentData
}
const olivetinVersion = window.initResponse?.currentVersion || t('diagnostics.unknown')
const showVersionNumber = window.initResponse?.effectivePolicy?.showVersionNumber ?? true
const olivetinVersion = showVersionNumber
? (window.initResponse?.currentVersion || t('diagnostics.unknown'))
: '[hidden]'
const currentLanguage = locale.value || t('diagnostics.unknown')
let output = '';

View File

@ -0,0 +1,13 @@
#
# Integration Test Config: xterm link handling
#
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
actions:
- title: Echo URL
shell: echo "See https://example.com for more info"
popupOnStart: execution-dialog-stdout-only

View File

@ -0,0 +1,69 @@
import { describe, it, before, after } from 'mocha'
import { expect } from 'chai'
import { By, Condition } from 'selenium-webdriver'
import {
getRootAndWait,
takeScreenshotOnFailure,
getTerminalBuffer,
} from '../../lib/elements.js'
describe('config: xtermLinkHandling', function () {
before(async function () {
await runner.start('xtermLinkHandling')
})
after(async () => {
await runner.stop()
})
afterEach(function () {
takeScreenshotOnFailure(this.currentTest, webdriver)
})
it('xterm output shows URL and link handling is configured', async function () {
await getRootAndWait()
await webdriver.wait(new Condition('wait for Echo URL button', async () => {
const btns = await webdriver.findElements(By.css('[title="Echo URL"]'))
return btns.length === 1
}), 10000)
const echoUrlButton = await webdriver.findElement(By.css('[title="Echo URL"]'))
await echoUrlButton.click()
await webdriver.wait(new Condition('wait for execution view', async () => {
const url = await webdriver.getCurrentUrl()
return url.includes('/logs/') && !url.endsWith('/logs')
}), 10000)
await webdriver.wait(new Condition('wait for execution status', async () => {
const statusElements = await webdriver.findElements(By.id('execution-dialog-status'))
return statusElements.length > 0
}), 5000)
await webdriver.wait(new Condition('wait for execution to finish', async () => {
try {
const statusElement = await webdriver.findElement(By.id('execution-dialog-status'))
const statusText = await statusElement.getText()
return !statusText.includes('Executing')
} catch (e) {
return false
}
}), 5000)
await webdriver.sleep(500)
const bufferText = await getTerminalBuffer()
expect(bufferText).to.not.be.null
expect(bufferText).to.include('https://example.com')
const linkHandlerSet = await webdriver.executeScript(`
try {
return !!(window.terminal && window.terminal.linkHandlerConfigured === true)
} catch (e) {
return false
}
`)
expect(linkHandlerSet).to.equal(true)
})
})

View File

@ -51,6 +51,7 @@ message GetDashboardResponse {
message EffectivePolicy {
bool show_diagnostics = 1;
bool show_log_list = 2;
bool show_version_number = 3;
}
message GetDashboardRequest {

View File

@ -410,11 +410,12 @@ func (x *GetDashboardResponse) GetDashboard() *Dashboard {
}
type EffectivePolicy struct {
state protoimpl.MessageState `protogen:"open.v1"`
ShowDiagnostics bool `protobuf:"varint,1,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
ShowLogList bool `protobuf:"varint,2,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
ShowDiagnostics bool `protobuf:"varint,1,opt,name=show_diagnostics,json=showDiagnostics,proto3" json:"show_diagnostics,omitempty"`
ShowLogList bool `protobuf:"varint,2,opt,name=show_log_list,json=showLogList,proto3" json:"show_log_list,omitempty"`
ShowVersionNumber bool `protobuf:"varint,3,opt,name=show_version_number,json=showVersionNumber,proto3" json:"show_version_number,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *EffectivePolicy) Reset() {
@ -461,6 +462,13 @@ func (x *EffectivePolicy) GetShowLogList() bool {
return false
}
func (x *EffectivePolicy) GetShowVersionNumber() bool {
if x != nil {
return x.ShowVersionNumber
}
return false
}
type GetDashboardRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
@ -3934,10 +3942,11 @@ const file_olivetin_api_v1_olivetin_proto_rawDesc = "" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"f\n" +
"\x14GetDashboardResponse\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x128\n" +
"\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"`\n" +
"\tdashboard\x18\x04 \x01(\v2\x1a.olivetin.api.v1.DashboardR\tdashboard\"\x90\x01\n" +
"\x0fEffectivePolicy\x12)\n" +
"\x10show_diagnostics\x18\x01 \x01(\bR\x0fshowDiagnostics\x12\"\n" +
"\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\"k\n" +
"\rshow_log_list\x18\x02 \x01(\bR\vshowLogList\x12.\n" +
"\x13show_version_number\x18\x03 \x01(\bR\x11showVersionNumber\"k\n" +
"\x13GetDashboardRequest\x12\x14\n" +
"\x05title\x18\x01 \x01(\tR\x05title\x12\x1f\n" +
"\ventity_type\x18\x02 \x01(\tR\n" +

View File

@ -1,6 +1,6 @@
module github.com/OliveTin/OliveTin
go 1.25.0
go 1.25.6
exclude google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884
@ -10,7 +10,7 @@ require (
github.com/MicahParks/keyfunc/v3 v3.8.0
github.com/PaesslerAG/jsonpath v0.1.1
github.com/alexedwards/argon2id v1.0.0
github.com/bufbuild/buf v1.65.0
github.com/bufbuild/buf v1.66.0
github.com/fsnotify/fsnotify v1.9.0
github.com/fzipp/gocyclo v0.6.0
github.com/go-critic/go-critic v0.14.3
@ -27,7 +27,7 @@ require (
github.com/sirupsen/logrus v1.9.4
github.com/stretchr/testify v1.11.1
go.akshayshah.org/connectproto v0.6.0
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa
golang.org/x/oauth2 v0.35.0
golang.org/x/sys v0.41.0
google.golang.org/protobuf v1.36.11
@ -45,7 +45,7 @@ require (
buf.build/go/bufplugin v0.9.0 // indirect
buf.build/go/bufprivateusage v0.1.0 // indirect
buf.build/go/interrupt v1.1.0 // indirect
buf.build/go/protovalidate v1.1.2 // indirect
buf.build/go/protovalidate v1.1.3 // indirect
buf.build/go/protoyaml v0.6.0 // indirect
buf.build/go/spdx v0.2.0 // indirect
buf.build/go/standard v0.1.0 // indirect
@ -57,7 +57,7 @@ require (
github.com/PaesslerAG/gval v1.2.4 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bufbuild/protocompile v0.14.2-0.20260130195850-5c64bed4577e // indirect
github.com/bufbuild/protocompile v0.14.2-0.20260202185951-d02d3732d113 // indirect
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cli/browser v1.3.0 // indirect
@ -90,7 +90,7 @@ require (
github.com/gofrs/flock v0.13.0 // indirect
github.com/google/cel-go v0.27.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry v0.20.7 // indirect
github.com/google/go-containerregistry v0.21.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jdx/go-netrc v1.0.0 // indirect
@ -155,8 +155,8 @@ require (
golang.org/x/text v0.34.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools v0.42.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d // indirect
google.golang.org/grpc v1.75.1 // indirect
mvdan.cc/xurls/v2 v2.6.0 // indirect
pluginrpc.com/pluginrpc v0.5.0 // indirect

View File

@ -32,6 +32,8 @@ buf.build/go/protovalidate v1.1.0 h1:pQqEQRpOo4SqS60qkvmhLTTQU9JwzEvdyiqAtXa5SeY
buf.build/go/protovalidate v1.1.0/go.mod h1:bGZcPiAQDC3ErCHK3t74jSoJDFOs2JH3d7LWuTEIdss=
buf.build/go/protovalidate v1.1.2 h1:83vYHoY8f34hB8MeitGaYE3CGVPFxwdEUuskh5qQpA0=
buf.build/go/protovalidate v1.1.2/go.mod h1:Ez3z+w4c+wG+EpW8ovgZaZPnPl2XVF6kaxgcv1NG/QE=
buf.build/go/protovalidate v1.1.3 h1:m2GVEgQWd7rk+vIoAZ+f0ygGjvQTuqPQapBBdcpWVPE=
buf.build/go/protovalidate v1.1.3/go.mod h1:9XIuohWz+kj+9JVn3WQneHA5LZP50mjvneZMnbLkiIE=
buf.build/go/protoyaml v0.6.0 h1:Nzz1lvcXF8YgNZXk+voPPwdU8FjDPTUV4ndNTXN0n2w=
buf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q=
buf.build/go/spdx v0.2.0 h1:IItqM0/cMxvFJJumcBuP8NrsIzMs/UYjp/6WSpq8LTw=
@ -84,6 +86,8 @@ github.com/bufbuild/buf v1.64.0 h1:puHWFcVKmZFSu4KuaN0kZiQ32n7VVc3un1FeLU77XUs=
github.com/bufbuild/buf v1.64.0/go.mod h1:U4ISwkjZXRLMaCkPG9zp1xY3xHEIwhCFwyNAaA56SGw=
github.com/bufbuild/buf v1.65.0 h1:f2BzeCY9rRh9P5KD340ZoPAaFLTkssoUTHx7lpqozgg=
github.com/bufbuild/buf v1.65.0/go.mod h1:7SAs2YqGpPXHqBBXBeYQbCzY0OQq4Jbg6XCqirEiYvQ=
github.com/bufbuild/buf v1.66.0 h1:6kksYJpu6r45bvPJSTwNSwRqiAjrwB9YyU7skjNzFVo=
github.com/bufbuild/buf v1.66.0/go.mod h1:tWVlwtIPZ7kzlCB9D0hbbfrroT0GNCybPdPQXq1i1Ac=
github.com/bufbuild/protocompile v0.14.2-0.20251223142729-db46c1b9d34e h1:LQA+1MyiPkolGHJGC2GMDC5Xu+0RDVH6jGMKech7Exs=
github.com/bufbuild/protocompile v0.14.2-0.20251223142729-db46c1b9d34e/go.mod h1:5UUj46Eu+U+C59C5N6YilaMI7WWfP2bW9xGcOkme2DI=
github.com/bufbuild/protocompile v0.14.2-0.20260105175043-4d8d90b1c6b8 h1:cQYwUyAzyMmYr7AyJU1C6pVCpUrJJBkmx7UunZosxxs=
@ -92,6 +96,8 @@ github.com/bufbuild/protocompile v0.14.2-0.20260120135352-a3ed5cd7a608 h1:3aRREB
github.com/bufbuild/protocompile v0.14.2-0.20260120135352-a3ed5cd7a608/go.mod h1:5UUj46Eu+U+C59C5N6YilaMI7WWfP2bW9xGcOkme2DI=
github.com/bufbuild/protocompile v0.14.2-0.20260130195850-5c64bed4577e h1:emH16Bf1w4C0cJ3ge4QtBAl4sIYJe23EfpWH0SpA9co=
github.com/bufbuild/protocompile v0.14.2-0.20260130195850-5c64bed4577e/go.mod h1:cxhE8h+14t0Yxq2H9MV/UggzQ1L0gh0t2tJobITWsBE=
github.com/bufbuild/protocompile v0.14.2-0.20260202185951-d02d3732d113 h1:nxt1QhP9rMQNFhHTdcNFwJ9wKCSdBjd28gz+qGDv4kM=
github.com/bufbuild/protocompile v0.14.2-0.20260202185951-d02d3732d113/go.mod h1:cxhE8h+14t0Yxq2H9MV/UggzQ1L0gh0t2tJobITWsBE=
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 h1:V1xulAoqLqVg44rY97xOR+mQpD2N+GzhMHVwJ030WEU=
github.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@ -200,6 +206,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I=
github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM=
github.com/google/go-containerregistry v0.21.0 h1:ocqxUOczFwAZQBMNE7kuzfqvDe0VWoZxQMOesXreCDI=
github.com/google/go-containerregistry v0.21.0/go.mod h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
@ -375,6 +383,7 @@ go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIl
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
@ -421,6 +430,8 @@ golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o=
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=
golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93 h1:PbC785RGO6yPO051ItgbG/adwoKRWC0VS7kXXeD/iqk=
@ -519,6 +530,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260122232226-8e98ce8d340d h1:
google.golang.org/genproto/googleapis/api v0.0.0-20260122232226-8e98ce8d340d/go.mod h1:p3MLuOwURrGBRoEyFHBT3GjUwaCQVKeNqqWxlcISGdw=
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0=
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d h1:EocjzKLywydp5uZ5tJ79iP6Q0UjDnyiHkGRWxuPBP8s=
google.golang.org/genproto/googleapis/api v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:48U2I+QQUYhsFrg2SY6r+nJzeOtjey7j//WBESw+qyQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
@ -527,6 +540,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d h1:t/LOSXPJ9R0B6fnZNyALBRfZBH0Uy0gT+uR+SJ6syqQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=

View File

@ -710,7 +710,9 @@ func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *connect.Request[apiv1.WhoAm
}
func (api *oliveTinAPI) SosReport(ctx ctx.Context, req *connect.Request[apiv1.SosReportRequest]) (*connect.Response[apiv1.SosReportResponse], error) {
sos := installationinfo.GetSosReport()
user := auth.UserFromApiCall(ctx, req, api.cfg)
redactVersion := !user.EffectivePolicy.ShowVersionNumber
sos := installationinfo.GetSosReport(redactVersion)
if !api.cfg.InsecureAllowDumpSos {
log.Info(sos)
@ -914,12 +916,19 @@ func (api *oliveTinAPI) Init(ctx ctx.Context, req *connect.Request[apiv1.InitReq
loginRequired := user.IsGuest() && api.cfg.AuthRequireGuestsToLogin
showVersion := user.EffectivePolicy.ShowVersionNumber
currentVersion := ""
availableVersion := ""
if showVersion {
currentVersion = installationinfo.Build.Version
availableVersion = installationinfo.Runtime.AvailableVersion
}
res := &apiv1.InitResponse{
ShowFooter: api.cfg.ShowFooter,
ShowNavigation: api.cfg.ShowNavigation,
ShowNewVersions: api.cfg.ShowNewVersions,
AvailableVersion: installationinfo.Runtime.AvailableVersion,
CurrentVersion: installationinfo.Build.Version,
ShowNewVersions: showVersion && api.cfg.ShowNewVersions,
AvailableVersion: availableVersion,
CurrentVersion: currentVersion,
PageTitle: api.cfg.PageTitle,
SectionNavigationStyle: api.cfg.SectionNavigationStyle,
DefaultIconForBack: api.cfg.DefaultIconForBack,

View File

@ -55,8 +55,9 @@ func matchesEntity(binding *executor.ActionBinding, entity *entities.Entity) boo
func buildEffectivePolicy(policy *config.ConfigurationPolicy) *apiv1.EffectivePolicy {
ret := &apiv1.EffectivePolicy{
ShowDiagnostics: policy.ShowDiagnostics,
ShowLogList: policy.ShowLogList,
ShowDiagnostics: policy.ShowDiagnostics,
ShowLogList: policy.ShowLogList,
ShowVersionNumber: policy.ShowVersionNumber,
}
return ret

View File

@ -76,8 +76,9 @@ func (u *AuthenticatedUser) BuildUserAcls(cfg *config.Config) {
func getEffectivePolicy(cfg *config.Config, u *AuthenticatedUser) *config.ConfigurationPolicy {
ret := &config.ConfigurationPolicy{
ShowDiagnostics: cfg.DefaultPolicy.ShowDiagnostics,
ShowLogList: cfg.DefaultPolicy.ShowLogList,
ShowDiagnostics: cfg.DefaultPolicy.ShowDiagnostics,
ShowLogList: cfg.DefaultPolicy.ShowLogList,
ShowVersionNumber: cfg.DefaultPolicy.ShowVersionNumber,
}
for _, acl := range cfg.AccessControlLists {
@ -98,5 +99,9 @@ func buildConfigurationPolicy(ret *config.ConfigurationPolicy, policy config.Con
ret.ShowLogList = policy.ShowLogList
}
if policy.ShowVersionNumber {
ret.ShowVersionNumber = policy.ShowVersionNumber
}
return ret
}

View File

@ -11,6 +11,7 @@ import (
"io"
"net/http"
"os"
"sync"
"time"
authTypes "github.com/OliveTin/OliveTin/internal/auth/authpublic"
@ -21,6 +22,7 @@ import (
type OAuth2Handler struct {
cfg *config.Config
mu sync.RWMutex
registeredStates map[string]*oauth2State
registeredProviders map[string]*oauth2.Config
}
@ -144,11 +146,13 @@ func (h *OAuth2Handler) HandleOAuthLogin(w http.ResponseWriter, r *http.Request)
return
}
h.mu.Lock()
h.registeredStates[state] = &oauth2State{
providerConfig: provider,
providerName: providerName,
Username: "",
}
h.mu.Unlock()
h.setOAuthCallbackCookie(w, r, "olivetin-sid-oauth", state)
@ -177,7 +181,9 @@ func (h *OAuth2Handler) checkOAuthCallbackCookie(w http.ResponseWriter, r *http.
return nil, state, false
}
h.mu.RLock()
registeredState, ok := h.registeredStates[state]
h.mu.RUnlock()
if !ok {
log.Errorf("State not found in server: %v", state)
http.Error(w, "State not found in server", http.StatusBadRequest)
@ -287,8 +293,10 @@ func (h *OAuth2Handler) HandleOAuthCallback(w http.ResponseWriter, r *http.Reque
userInfoClient := h.createUserInfoClient(ctx, registeredState.providerConfig, tok, clientSettings)
userinfo := getUserInfo(h.cfg, userInfoClient, providerConfig)
h.mu.Lock()
h.registeredStates[state].Username = userinfo.Username
h.registeredStates[state].Usergroup = h.computeUsergroup(userinfo, providerConfig)
h.mu.Unlock()
http.Redirect(w, r, "/", http.StatusFound)
}
@ -366,34 +374,36 @@ func getDataField(data map[string]any, field string) string {
return stringVal
}
func (h *OAuth2Handler) lookupOAuth2UserByState(state string) (*authTypes.AuthenticatedUser, bool) {
h.mu.RLock()
serverState, found := h.registeredStates[state]
if !found {
h.mu.RUnlock()
return nil, false
}
user := &authTypes.AuthenticatedUser{
Username: serverState.Username,
UsergroupLine: serverState.Usergroup,
Provider: "oauth2",
SID: state,
}
h.mu.RUnlock()
return user, true
}
func (h *OAuth2Handler) CheckUserFromOAuth2Cookie(context *authTypes.AuthCheckingContext) *authTypes.AuthenticatedUser {
cookie, err := context.Request.Cookie("olivetin-sid-oauth")
user := &authTypes.AuthenticatedUser{}
if err != nil {
if err != nil || cookie.Value == "" {
return nil
}
if cookie.Value == "" {
return nil
}
serverState, found := h.registeredStates[cookie.Value]
user, found := h.lookupOAuth2UserByState(cookie.Value)
if !found {
log.WithFields(log.Fields{
"sid": cookie.Value,
"provider": "oauth2",
}).Warnf("Stale session")
return nil
}
user.Username = serverState.Username
user.UsergroupLine = serverState.Usergroup
user.Provider = "oauth2"
user.SID = cookie.Value
return user
}

View File

@ -98,8 +98,9 @@ type AccessControlList struct {
// ConfigurationPolicy defines global settings which are overridden with an ACL.
type ConfigurationPolicy struct {
ShowDiagnostics bool `koanf:"showDiagnostics"`
ShowLogList bool `koanf:"showLogList"`
ShowDiagnostics bool `koanf:"showDiagnostics"`
ShowLogList bool `koanf:"showLogList"`
ShowVersionNumber bool `koanf:"showVersionNumber"`
}
type PrometheusConfig struct {
@ -297,6 +298,7 @@ func DefaultConfigWithBasePort(basePort int) *Config {
config.DefaultPolicy.ShowDiagnostics = true
config.DefaultPolicy.ShowLogList = true
config.DefaultPolicy.ShowVersionNumber = true
return &config
}

View File

@ -164,6 +164,7 @@ func (cfg *Config) sanitizeAuthRequireGuestsToLogin() {
cfg.DefaultPermissions.View = false
cfg.DefaultPermissions.Exec = false
cfg.DefaultPermissions.Logs = false
cfg.DefaultPermissions.Kill = false
}
}

View File

@ -40,15 +40,23 @@ func configToSosreport(cfg *config.Config) *sosReportConfig {
}
}
func GetSosReport() string {
func GetSosReport(redactVersion bool) string {
ret := ""
ret += "### SOSREPORT START (copy all text to SOSREPORT END)\n"
out, _ := yaml.Marshal(Build)
buildForReport := *Build
if redactVersion {
buildForReport.Version = "[redacted]"
}
out, _ := yaml.Marshal(&buildForReport)
ret += fmt.Sprintf("# Build: \n%+v\n", string(out))
out, _ = yaml.Marshal(Runtime)
runtimeForReport := *Runtime
if redactVersion {
runtimeForReport.AvailableVersion = "[redacted]"
}
out, _ = yaml.Marshal(&runtimeForReport)
ret += fmt.Sprintf("# Runtime:\n%+v\n", string(out))
out, _ = yaml.Marshal(configToSosreport(Config))