Compare commits

..
1 Commits
Author SHA1 Message Date
micbar 6eaa5bae63 Use omega branch for web 2026-08-06 10:32:32 +02:00
1085 changed files with 20901 additions and 80478 deletions

No files matched your search

-153
View File
@@ -1,153 +0,0 @@
---
name: bumping-reva
description: Use when the user asks to bump, update, or upgrade the OpenCloud reva dependency to a specific version (e.g. "reva bump to 2.48.0", "bump reva to v2.48.0"). Covers editing go.mod, re-vendoring, bumping the OpenCloud LatestTag, the single commit, and opening the PR against main.
---
# Bumping Reva
## Overview
Bumping reva updates the pinned [opencloud-eu/reva](https://github.com/opencloud-eu/reva) dependency (`github.com/opencloud-eu/reva/v2`) to a tagged release, re-vendors the module graph, and bumps the OpenCloud dev version. It touches `go.mod`, `go.sum`, `vendor/**` and `pkg/version/version.go`, lands as one commit, and ships as a PR whose body is the reva changelog for that version.
Template PR: https://github.com/opencloud-eu/opencloud/pull/3127
## Prerequisites
- **The reva release must already be tagged.** A reva release is cut by merging its release PR (title `🎉 Release X.Y.Z`, branch `next-release/main`). The **user merges that PR themselves** — this skill starts *after* the tag `vX.Y.Z` exists. Verify the tag before doing anything (step 1); if it's missing, stop and ask the user to merge the reva release PR first.
- **`gh` (GitHub CLI), authenticated** — tag lookup and PR creation go through `gh api` / `gh pr`. Verify with `gh auth status`; if it fails, ask the user to run `gh auth login` (suggest `! gh auth login` so it runs in-session).
- `gh` needs the system keyring, so run all `gh` commands with the sandbox disabled.
- **Go toolchain + network** — `go get` / `go mod tidy` / `go mod vendor` hit the Go module proxy. Run them with the sandbox disabled (network access).
- `git` and `base64` (decoding the changelog) — standard on macOS/Linux.
## Inputs
- `REVA_VERSION` — the new reva tag, always normalized to a leading `v` (e.g. `v2.48.0`). If the user didn't give it, ask (or take the latest reva release tag).
- `OC_VERSION` — the OpenCloud target for `LatestTag`, **without** the `+dev` suffix (e.g. `7.4.0`). **Do not ask or guess** — derive it from the open OpenCloud release PR (step 3). It can be a new major (e.g. `8.0.0`) when release-please picked up a breaking change.
## What changes
| File | What |
| ------------------------ | ------------------------------------------------------------------- |
| `go.mod` | `github.com/opencloud-eu/reva/v2``REVA_VERSION` (+ indirect deps pulled by `go mod tidy`) |
| `go.sum` | updated by `go get` / `go mod tidy` |
| `vendor/**` | re-vendored by `go mod vendor` (incl. `vendor/modules.txt`) |
| `pkg/version/version.go` | `LatestTag = "<OC_VERSION>+dev"` |
## Procedure
### 1. Verify the reva tag exists
```bash
gh api repos/opencloud-eu/reva/commits/$REVA_VERSION --jq '.sha'
```
- Success (a sha) → the release is tagged, continue.
- `422`/`404` → the tag does not exist yet. The reva release PR (`🎉 Release X.Y.Z`) is probably not merged. **Stop** and tell the user to merge it first. Helpful checks:
```bash
gh api repos/opencloud-eu/reva/releases/latest --jq '.tag_name' # current latest tag
gh pr list --repo opencloud-eu/reva --search '🎉 Release in:title' --state open --json number,title
```
### 2. Bump the dependency and re-vendor
```bash
go get github.com/opencloud-eu/reva/v2@$REVA_VERSION
go mod tidy
go mod vendor
```
(Sandbox disabled — these need network.) Notes:
- Right after a fresh tag the module proxy can lag; if `go get` reports the version as unknown, retry, or use `GOPROXY=direct go get github.com/opencloud-eu/reva/v2@$REVA_VERSION`.
- `go mod tidy` will also bump indirect dependencies that reva pulled in — that is expected (the template PR did the same).
### 3. Bump the OpenCloud dev version
`OC_VERSION` is the version of the **open OpenCloud release PR** — the release-please PR from branch `next-release/main`, titled `🎉 Release X.Y.Z` (e.g. #3143). Derive it, don't ask:
```bash
gh pr list --repo opencloud-eu/opencloud --head next-release/main --state open \
--json title --jq '.[0].title' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1
```
This is the next release target and tracks breaking changes — it may be a new major (e.g. `8.0.0`), not just a minor bump. If no such PR is open, stop and ask the user.
Edit `pkg/version/version.go`:
```go
LatestTag = "<OC_VERSION>+dev" // e.g. "7.4.0+dev"
```
### 4. Fetch the reva changelog for the PR body
```bash
gh api "repos/opencloud-eu/reva/contents/CHANGELOG.md?ref=$REVA_VERSION" --jq '.content' | base64 -d
```
Take **only the section for this version** and trim it exactly like the web bump: start at the first content heading (`### 🐛 Bug Fixes` / `### 📈 Enhancement` / `### 💥 Breaking changes`), drop the `# Changelog` title, the `## [x.y.z] - date` header and the `### ❤️ Thanks to all contributors!` block, and stop before the next `## [...]` version header.
Then **prepend two summary bullets** so the final PR body is:
```
- bump opencloud version to <OC_VERSION>
- reva bump <REVA_VERSION without the leading v>
### 🐛 Bug Fixes
...trimmed reva changelog...
```
Write this to a file for `--body-file` (e.g. in the scratchpad).
### 5. Confirm before committing
The `vendor/` diff is huge — do **not** dump it. Show the user:
```bash
git diff go.mod pkg/version/version.go # the meaningful edits
git diff --stat | tail -1 # vendor churn summary
```
Confirm the reva line in `go.mod` is exactly `github.com/opencloud-eu/reva/v2 REVA_VERSION`, show the target branch (`main`), and the PR body. **Do not commit until the user approves.**
### 6. Commit, push, open PR
- Create a branch (do not commit on `main`), e.g. `reva-bump-2.48.0`.
- Stage everything the bump touched: `git add go.mod go.sum vendor pkg/version/version.go`.
- One commit, conventional-commits format, **empty body**:
```
chore: bump reva to 2.48.0
```
- PR base: **`main`** (reva bumps always target main).
- PR title: `[full-ci] chore: bump reva to 2.48.0` (the commit message prefixed with `[full-ci] `).
- PR body: the file from step 4.
- Add the label `Type:Maintenance`.
```bash
gh pr create --base main \
--title "[full-ci] chore: bump reva to $REVA_VERSION_NO_V" \
--label "Type:Maintenance" \
--body-file <body-file>
```
(`gh` commands need the sandbox disabled — they require the system keyring.)
## Quick reference
```bash
REVA_VERSION=v2.48.0
gh api repos/opencloud-eu/reva/commits/$REVA_VERSION --jq '.sha' # verify tag exists
OC_VERSION=$(gh pr list --repo opencloud-eu/opencloud --head next-release/main --state open \
--json title --jq '.[0].title' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) # from open release PR
go get github.com/opencloud-eu/reva/v2@$REVA_VERSION && go mod tidy && go mod vendor # bump + re-vendor
# edit pkg/version/version.go -> LatestTag = "$OC_VERSION+dev"
gh api "repos/opencloud-eu/reva/contents/CHANGELOG.md?ref=$REVA_VERSION" --jq '.content' | base64 -d # changelog
```
## Common mistakes
- Running the bump before the reva release PR is merged — the tag won't exist and `go get` will fail. Verify the tag first (step 1).
- Forgetting to re-run `go mod vendor` after `go mod tidy`, leaving `vendor/` out of sync with `go.mod`.
- Asking for or hardcoding `OC_VERSION` — always derive it from the open `next-release/main` release PR (step 3); it can even be a new major after a breaking change.
- Reading the changelog from reva `main` instead of the tag (`?ref=$REVA_VERSION`). Always pin to the tag.
- Missing the `[full-ci] ` prefix in the PR title, the `Type:Maintenance` label, or the two summary bullets at the top of the body.
- Dumping the full `vendor/` diff at the confirmation step instead of `go.mod` + `version.go` + a `--stat` summary.
- Committing before the user confirms the diff.
-1
View File
@@ -1,7 +1,6 @@
---
exclude_paths:
- '.github/**'
- '.agents/**'
- 'CHANGELOG.md'
- '**/CHANGELOG.md'
- 'changelog/**'
+3 -5
View File
@@ -2,8 +2,6 @@
[Release Template](https://github.com/opencloud-eu/opencloud/blob/main/.github/rolling_release_template.md)
## Prerequisites
* [ ] replace `%%NEXT%%` with the release version
* [ ] web release
* [ ] bump web version
* [ ] squash and merge the web release PR
@@ -16,17 +14,17 @@
## QA Phase
* [ ] bump `opencloud_commitid` in web and run all working tests in CI
* [ ] compatibility test
* [ ] n8n integration QA
* [ ] confirmatory testing, if needed
* [ ] squash and merge Release PR
## Collected bugs
## After QA Phase
* [ ] replace `%%NEXT%%` wuth the release version
* [ ] squash and merge Release PR
* [ ] publish release notes to the docs
* [ ] add migration guide to changelog with prefix `**ACTION REQUIRED:**`, if needed.
* [ ] add release notes from web and reva to opencloud changelog
* [ ] n8n integration - update new opencloud version
* [ ] docker-compose - update new opencloud version
* [ ] update the public matrix channel topic
* [ ] update https://update.opencloud.eu/server.json
* [ ] update the version on demo.opencloud.eu
+1
View File
@@ -36,6 +36,7 @@ vendor-bin/**/composer.lock
vendor-php
# API acceptance tests - auto-generated files
.php-cs-fixer.cache
suite-logs
tests/acceptance/filesForUpload/filesWithVirus/
+31
View File
@@ -0,0 +1,31 @@
<?php
$dirToParse = 'tests/acceptance/';
$dirIterator = new DirectoryIterator(__DIR__ . '/' . $dirToParse);
$excludeDirs = [
'node_modules',
'vendor-php'
];
$finder = PhpCsFixer\Finder::create()
->exclude($excludeDirs)
->in(__DIR__);
$ocRule = (new OC\CodingStandard\Config())->getRules();
$config = new PhpCsFixer\Config();
$config->setFinder($finder)
->setIndent("\t")
->setRules(
array_merge(
$ocRule,
[
"return_type_declaration" => [
"space_before" => "none",
],
'single_space_around_construct' => true
]
)
);
$config->setFinder($finder);
return $config;
+1 -1
View File
@@ -1,3 +1,3 @@
# The test runner source for UI tests
WEB_COMMITID=dffb3808702dab198065faa7a8aa16228e048385
WEB_COMMITID=7bc6f96066e0618c301ee34cb7fe219efd47e3c0
WEB_BRANCH=main
+68 -86
View File
@@ -202,14 +202,12 @@ config = {
"apiSearch1",
],
"skip": False,
"nightlyOpenSearch": True,
},
"search2": {
"suites": [
"apiSearch2",
],
"skip": False,
"nightlyOpenSearch": True,
},
"sharingNg": {
"suites": [
@@ -273,7 +271,6 @@ config = {
],
"skip": False,
"tikaNeeded": True,
"nightlyOpenSearch": True,
},
"ocm": {
"suites": [
@@ -820,7 +817,30 @@ def testOpencloud(ctx):
],
"environment": CI_HTTP_PROXY_ENV,
},
] + waitForOpenSearch() + [
{
"name": "open-search",
"image": OPEN_SEARCH,
"detach": True,
"environment": {
"discovery.type": "single-node",
"DISABLE_INSTALL_DEMO_CONFIG": True,
"DISABLE_SECURITY_PLUGIN": True,
},
"entrypoint": ["/usr/share/opensearch/opensearch-docker-entrypoint.sh", "opensearch"],
},
{
"name": "wait-for-open-search",
"image": OC_CI_ALPINE,
"commands": [
"bash -c '" +
"until curl -sS \"http://open-search:9200/_cat/health?h=status\" | grep \"green\\|yellow\"; do\n" +
" echo \"Waiting for http://open-search:9200 to be healthy...\"\n" +
" sleep 5\n" +
"done\n" +
"echo \"http://open-search:9200 healthy...\"\n" +
"'",
],
},
{
"name": "test",
"image": OC_CI_GOLANG,
@@ -852,7 +872,6 @@ def testOpencloud(ctx):
pipeline = {
"name": "test-lint-unit",
"steps": steps,
"services": openSearchService(),
"when": [
event["base"],
event["cron"],
@@ -919,6 +938,30 @@ def buildOpencloudBinaryForTesting(ctx):
}
return [pipeline]
def vendorbinCodestyle(phpVersion):
return [{
"name": "vendorbin-codestyle",
"image": OC_CI_PHP % phpVersion,
"environment": {
"COMPOSER_HOME": "%s/.cache/composer" % dirs["base"],
},
"commands": [
"make vendor-bin-codestyle",
],
}]
def vendorbinCodesniffer(phpVersion):
return [{
"name": "vendorbin-codesniffer",
"image": OC_CI_PHP % phpVersion,
"environment": {
"COMPOSER_HOME": "%s/.cache/composer" % dirs["base"],
},
"commands": [
"make vendor-bin-codesniffer",
],
}]
def checkTestSuitesInExpectedFailures(ctx):
return [{
"name": "check-suites-in-expected-failures",
@@ -1006,22 +1049,24 @@ def codestyle(ctx):
result = {
"name": name,
"steps": [
{
"name": "php-style",
"image": OC_CI_PHP % phpVersion,
"commands": [
"make test-php-style",
],
},
{
"name": "check-env-var-annotations",
"image": OC_CI_PHP % phpVersion,
"commands": [
"make check-env-var-annotations",
],
},
],
"steps": vendorbinCodestyle(phpVersion) +
vendorbinCodesniffer(phpVersion) +
[
{
"name": "php-style",
"image": OC_CI_PHP % phpVersion,
"commands": [
"make test-php-style",
],
},
{
"name": "check-env-var-annotations",
"image": OC_CI_PHP % phpVersion,
"commands": [
"make check-env-var-annotations",
],
},
],
"depends_on": [],
"when": [
event["base"],
@@ -1239,31 +1284,14 @@ def build_api_test_workflow_matrix(ctx, storage, suite_cfg, default_cfg):
matrix = {
"withRemotePhp": m["withRemotePhp"],
"enableWatchFs": m["enableWatchFs"],
"openSearch": False,
}
if override_with_remote_php != None:
matrix["withRemotePhp"] = override_with_remote_php
if override_enable_watch_fs != None:
matrix["enableWatchFs"] = override_enable_watch_fs
base = {
"withRemotePhp": matrix["withRemotePhp"],
"enableWatchFs": matrix["enableWatchFs"],
}
if matrix not in workflow_metrices and base in matrices:
if matrix not in workflow_metrices and matrix in matrices:
workflow_metrices.append(matrix)
# Add an OpenSearch search-engine variant for nightly running search tests,
# or on demand when "opensearch" is specified in the PR title
run_open_search = ctx.build.event == "cron" or "opensearch" in ctx.build.title.lower()
if run_open_search and storage == "posix" and suite_cfg.get("nightlyOpenSearch", False):
os_matrix = {
"withRemotePhp": False,
"enableWatchFs": False,
"openSearch": True,
}
if os_matrix not in workflow_metrices:
workflow_metrices.append(os_matrix)
return workflow_metrices
def localApiTestPipeline(ctx):
@@ -1284,7 +1312,6 @@ def localApiTestPipeline(ctx):
"withRemotePhp": False,
"enableWatchFs": False,
"ldapNeeded": False,
"nightlyOpenSearch": False,
}
if "localApiTests" in config:
@@ -1310,7 +1337,6 @@ def localApiTestPipeline(ctx):
for m in matrices:
run_with_remote_php = m["withRemotePhp"]
run_with_watch_fs = m["enableWatchFs"]
run_with_open_search = m["openSearch"]
pipeline_name = "test-API"
if name.startswith("cli"):
@@ -1321,19 +1347,11 @@ def localApiTestPipeline(ctx):
pipeline_name += "-withRemotePhp"
if run_with_watch_fs:
pipeline_name += "-watchfs"
if run_with_open_search:
pipeline_name += "-opensearch"
server_environment = dict(params["extraServerEnvironment"])
if run_with_open_search:
server_environment["SEARCH_ENGINE_TYPE"] = "open-search"
server_environment["SEARCH_ENGINE_OPEN_SEARCH_CLIENT_ADDRESSES"] = "http://open-search:9200"
pipeline = {
"name": pipeline_name,
"steps": evaluateWorkflowStep() + restoreBuildArtifactCache(ctx, dirs["opencloudBinArtifact"], dirs["opencloudBinPath"]) +
(tikaService() if params["tikaNeeded"] else []) +
(waitForOpenSearch() if run_with_open_search else []) +
(waitForWebOffices(["https://collabora:9980", "https://onlyoffice", "http://fakeoffice:8080"]) if params["collaborationServiceNeeded"] else []) +
(waitForClamavService() if params["antivirusNeeded"] else []) +
(waitForEmailService() if params["emailNeeded"] else []) +
@@ -1341,7 +1359,7 @@ def localApiTestPipeline(ctx):
(waitForLdapService() if params["ldapNeeded"] else []) +
opencloudServer(
storage,
extra_server_environment = server_environment,
extra_server_environment = params["extraServerEnvironment"],
with_wrapper = True,
tika_enabled = params["tikaNeeded"],
watch_fs_enabled = run_with_watch_fs,
@@ -1353,7 +1371,6 @@ def localApiTestPipeline(ctx):
logRequests(),
"services": (emailService() if params["emailNeeded"] else []) +
(clamavService() if params["antivirusNeeded"] else []) +
(openSearchService() if run_with_open_search else []) +
((fakeOffice() + collaboraService() + onlyofficeService()) if params["collaborationServiceNeeded"] else []),
"depends_on": getPipelineNames(buildOpencloudBinaryForTesting(ctx)),
"when": [
@@ -1889,9 +1906,6 @@ def dockerRelease(ctx, repo, build_type):
"EDITION": "stable" if build_type == "production" else "rolling",
}
if ctx.build.event != "tag":
build_args["STRING"] = ctx.build.commit[:8]
# if no additional tag is given, the build-plugin adds latest
hard_tag = "daily"
if ctx.build.event == "tag":
@@ -2446,7 +2460,6 @@ def opencloudServer(storage = "decomposed", depends_on = [], deploy_type = "", e
"EVENTHISTORY_STORE": "memory",
"OC_TRANSLATION_PATH": "%s/tests/config/translations" % dirs["base"],
"ACTIVITYLOG_WRITE_BUFFER_DURATION": "0", # Disable write buffer so that test expectations are met in time
"OC_LDAP_LOOKUP_CACHE_TTL": "0", # disable ldap lookup cache so that test fixture change are applied right away
# search grpc port needed for index cli tests
"SEARCH_GRPC_ADDR": "0.0.0.0:9220",
# debug addresses required for running services health tests
@@ -2499,14 +2512,10 @@ def opencloudServer(storage = "decomposed", depends_on = [], deploy_type = "", e
if deploy_type == "cs3api_validator":
environment["GATEWAY_GRPC_ADDR"] = "0.0.0.0:9142" # make gateway available to cs3api-validator
environment["STORAGE_USERS_HTTP_ADDR"] = "0.0.0.0:9158" # make dataprovider available to wopi server
environment["STORAGE_USERS_DATA_SERVER_URL"] = "http://opencloud-server:9158/data" # make dataprovider routable by wopi server
environment["OC_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD"] = False
if deploy_type == "wopi_validator":
environment["GATEWAY_GRPC_ADDR"] = "0.0.0.0:9142" # make gateway available to wopi server
environment["STORAGE_USERS_HTTP_ADDR"] = "0.0.0.0:9158" # make dataprovider available to wopi server
environment["STORAGE_USERS_DATA_SERVER_URL"] = "http://opencloud-server:9158/data" # make dataprovider routable by wopi server
environment["APP_PROVIDER_EXTERNAL_ADDR"] = "eu.opencloud.api.app-provider"
environment["APP_PROVIDER_DRIVER"] = "wopi"
environment["APP_PROVIDER_WOPI_APP_NAME"] = "FakeOffice"
@@ -3424,33 +3433,6 @@ def tikaService():
],
}]
def openSearchService():
return [{
"name": "open-search",
"image": OPEN_SEARCH,
"environment": {
"discovery.type": "single-node",
"DISABLE_INSTALL_DEMO_CONFIG": True,
"DISABLE_SECURITY_PLUGIN": True,
},
"entrypoint": ["/usr/share/opensearch/opensearch-docker-entrypoint.sh", "opensearch"],
}]
def waitForOpenSearch():
return [{
"name": "wait-for-open-search",
"image": OC_CI_ALPINE,
"commands": [
"bash -c '" +
"until curl -sS \"http://open-search:9200/_cat/health?h=status\" | grep \"green\\|yellow\"; do\n" +
" echo \"Waiting for http://open-search:9200 to be healthy...\"\n" +
" sleep 5\n" +
"done\n" +
"echo \"http://open-search:9200 healthy...\"\n" +
"'",
],
}]
def logRequests():
return [{
"name": "api-test-failure-logs",
-120
View File
@@ -1,125 +1,5 @@
# Changelog
## [7.5.0](https://github.com/opencloud-eu/opencloud/releases/tag/v7.5.0) - 2026-08-25
### ❤️ Thanks to all contributors! ❤️
@AlexAndBear, @JammingBen, @Svanvith, @aduffeck, @butonic, @fschade, @junkerderprovinz, @kulmann, @maki5, @pbleser-oc, @rhafer, @saw-jan, @schweigisito, @v-scharf
### ✅ Tests
- test(api): update php test dependencies [[#3335](https://github.com/opencloud-eu/opencloud/pull/3335)]
- fix(acceptance): fix running acceptance tests against host on Linux [[#3358](https://github.com/opencloud-eu/opencloud/pull/3358)]
- fix(graph): adding the same user as multiple members in a group (#3354) [[#3356](https://github.com/opencloud-eu/opencloud/pull/3356)]
- test(api): fix share role update test scenario [[#3322](https://github.com/opencloud-eu/opencloud/pull/3322)]
- test: add api tests for cross-space search index mutation [[#3320](https://github.com/opencloud-eu/opencloud/pull/3320)]
- ci: run search acceptance tests against OpenSearch in nightly [[#3302](https://github.com/opencloud-eu/opencloud/pull/3302)]
- api-test: notification settings and getting email notifications [[#3281](https://github.com/opencloud-eu/opencloud/pull/3281)]
- api-test: add posixfs scan and consistency CLI tests [[#3263](https://github.com/opencloud-eu/opencloud/pull/3263)]
- api-test: replace sleeps with WaitHelper poll for async state [[#3239](https://github.com/opencloud-eu/opencloud/pull/3239)]
### 📈 Enhancement
- feat(thumbnails): extend list of default resolutions [[#3386](https://github.com/opencloud-eu/opencloud/pull/3386)]
- ability to disable grpc and/or event consumer for event history service [[#3279](https://github.com/opencloud-eu/opencloud/pull/3279)]
- feat(graph): add LibreGraphContentType on drive [[#3355](https://github.com/opencloud-eu/opencloud/pull/3355)]
- feat: update space template image [[#3324](https://github.com/opencloud-eu/opencloud/pull/3324)]
- feat(web): add rclone-crypt to default apps [[#3313](https://github.com/opencloud-eu/opencloud/pull/3313)]
- enhance: send events for adding/removing favourite items [[#3229](https://github.com/opencloud-eu/opencloud/pull/3229)]
- allow tuning the proxies http client [[#3278](https://github.com/opencloud-eu/opencloud/pull/3278)]
- feat(web): add yjsServerUrl config [[#3259](https://github.com/opencloud-eu/opencloud/pull/3259)]
- feat(posixfs): #3182 add basepath option in the "posixfs scan" command [[#3235](https://github.com/opencloud-eu/opencloud/pull/3235)]
### 🐛 Bug Fixes
- fix(search): refresh the opensearch index after a write [[#3388](https://github.com/opencloud-eu/opencloud/pull/3388)]
- fix(thumbnails): respect the requested height in libvips builds [[#3377](https://github.com/opencloud-eu/opencloud/pull/3377)]
- refactor datagateway into proxy middleware [[#3289](https://github.com/opencloud-eu/opencloud/pull/3289)]
- Only log a debug message when an item is still in processing state [[#3158](https://github.com/opencloud-eu/opencloud/pull/3158)]
- fix(postprocessing): retry publishing events instead of killing the server [[#3347](https://github.com/opencloud-eu/opencloud/pull/3347)]
- actually log error on exit [[#3344](https://github.com/opencloud-eu/opencloud/pull/3344)]
- fix(activitylog): log missing parent id cache entry at debug level [[#3325](https://github.com/opencloud-eu/opencloud/pull/3325)]
- fix restore file version for shared resource [[#3268](https://github.com/opencloud-eu/opencloud/pull/3268)]
- Fix missing favorite flag on opensearch hits [[#3252](https://github.com/opencloud-eu/opencloud/pull/3252)]
### 📚 Documentation
- docs: clarify custom role bootstrap behavior [[#3366](https://github.com/opencloud-eu/opencloud/pull/3366)]
### 📦️ Dependencies
- [full-ci] chore: bump web to v7.4.0 [[#3399](https://github.com/opencloud-eu/opencloud/pull/3399)]
- build(deps): bump google.golang.org/grpc from 1.83.0 to 1.83.1 [[#3396](https://github.com/opencloud-eu/opencloud/pull/3396)]
- build(deps): bump github.com/stretchr/testify from 1.12.0 to 1.12.1 [[#3395](https://github.com/opencloud-eu/opencloud/pull/3395)]
- build(deps): bump github.com/go-chi/chi/v5 from 5.3.1 to 5.3.2 [[#3394](https://github.com/opencloud-eu/opencloud/pull/3394)]
- build(deps): bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.29.0 to 2.30.0 [[#3380](https://github.com/opencloud-eu/opencloud/pull/3380)]
- build(deps): bump golang.org/x/image from 0.44.0 to 0.45.0 [[#3381](https://github.com/opencloud-eu/opencloud/pull/3381)]
- build(deps): bump github.com/beevik/etree from 1.7.0 to 1.7.1 [[#3382](https://github.com/opencloud-eu/opencloud/pull/3382)]
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.14.4 to 2.14.5 [[#3357](https://github.com/opencloud-eu/opencloud/pull/3357)]
- build(deps): bump go.opentelemetry.io/contrib/zpages from 0.69.0 to 0.70.0 [[#3360](https://github.com/opencloud-eu/opencloud/pull/3360)]
- build(deps): bump github.com/sirupsen/logrus from 1.9.4 to 1.10.0 [[#3359](https://github.com/opencloud-eu/opencloud/pull/3359)]
- chore: bump reva to latest main [[#3329](https://github.com/opencloud-eu/opencloud/pull/3329)]
- build(deps): bump github.com/stretchr/testify from 1.11.1 to 1.12.0 [[#3341](https://github.com/opencloud-eu/opencloud/pull/3341)]
- build(deps): bump golang.org/x/net from 0.57.0 to 0.58.0 [[#3342](https://github.com/opencloud-eu/opencloud/pull/3342)]
- build(deps): bump github.com/onsi/ginkgo/v2 from 2.32.0 to 2.32.1 [[#3340](https://github.com/opencloud-eu/opencloud/pull/3340)]
- build(deps): bump github.com/testcontainers/testcontainers-go/modules/opensearch from 0.43.0 to 0.44.0 [[#3303](https://github.com/opencloud-eu/opencloud/pull/3303)]
- build(deps): bump github.com/opencloud-eu/libre-graph-api-go [[#3326](https://github.com/opencloud-eu/opencloud/pull/3326)]
- build(deps): bump go.opentelemetry.io/otel/exporters/stdout/stdouttrace from 1.44.0 to 1.45.0 [[#3306](https://github.com/opencloud-eu/opencloud/pull/3306)]
- build(deps): bump go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from 0.69.0 to 0.70.0 [[#3305](https://github.com/opencloud-eu/opencloud/pull/3305)]
- build(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc from 1.44.0 to 1.45.0 [[#3280](https://github.com/opencloud-eu/opencloud/pull/3280)]
- build(deps): bump github.com/rogpeppe/go-internal from 1.15.0 to 1.16.0 [[#3250](https://github.com/opencloud-eu/opencloud/pull/3250)]
- build(deps): bump github.com/kovidgoyal/imaging from 1.8.22 to 1.8.23 [[#3135](https://github.com/opencloud-eu/opencloud/pull/3135)]
- build(deps): bump go.opentelemetry.io/otel/trace from 1.44.0 to 1.45.0 [[#3266](https://github.com/opencloud-eu/opencloud/pull/3266)]
## [7.4.0](https://github.com/opencloud-eu/opencloud/releases/tag/v7.4.0) - 2026-08-03
### ❤️ Thanks to all contributors! ❤️
@AlexAndBear, @JammingBen, @aduffeck, @dschmidt, @fschade, @michaelstingl, @pbleser-oc, @rhafer, @schweigisito, @v-scharf
### 📈 Enhancement
- Do not check ignored paths [[#3233](https://github.com/opencloud-eu/opencloud/pull/3233)]
- Extend posixfs consistency check [[#3220](https://github.com/opencloud-eu/opencloud/pull/3220)]
- Improve reindex command [[#3213](https://github.com/opencloud-eu/opencloud/pull/3213)]
- Reindex spaces concurrently [[#3207](https://github.com/opencloud-eu/opencloud/pull/3207)]
- feat: add announcement banner [[#3189](https://github.com/opencloud-eu/opencloud/pull/3189)]
- feat: add space viewer with versions role [[#2961](https://github.com/opencloud-eu/opencloud/pull/2961)]
### 🐛 Bug Fixes
- fix(runtime): log service startup errors instead of printing them beside the log [[#3140](https://github.com/opencloud-eu/opencloud/pull/3140)]
- fix(posixfs scan): Setup logger for scan command [[#3185](https://github.com/opencloud-eu/opencloud/pull/3185)]
### ✅ Tests
- api-test: mark group last-manager removal scenario as flaky [[#3194](https://github.com/opencloud-eu/opencloud/pull/3194)]
- rerun flaky tests [[#3183](https://github.com/opencloud-eu/opencloud/pull/3183)]
- api-test: fix removeAccessToDrive.feature:145 [[#3179](https://github.com/opencloud-eu/opencloud/pull/3179)]
- api-test: cover additional unified roles in acceptance tests [[#3169](https://github.com/opencloud-eu/opencloud/pull/3169)]
- test(apiAuthApp): fix flaky token pattern [[#3163](https://github.com/opencloud-eu/opencloud/pull/3163)]
- test(apiArchiver): the single-resource archive is named after the resource [[#3080](https://github.com/opencloud-eu/opencloud/pull/3080)]
- test(coreApiWebdavUploadTUS): assert etag and permissions on the finalizing TUS chunk [[#3078](https://github.com/opencloud-eu/opencloud/pull/3078)]
- test(coreApiWebdavOperations): download a file with a literal "%" via its oc:downloadURL [[#3079](https://github.com/opencloud-eu/opencloud/pull/3079)]
### 📚 Documentation
- maint: clean-up auth-app documentation [[#3155](https://github.com/opencloud-eu/opencloud/pull/3155)]
- ci: sync tests/README.md to docs [[#3164](https://github.com/opencloud-eu/opencloud/pull/3164)]
### 📦️ Dependencies
- [full-ci] chore: bump web to v7.3.0 [[#3223](https://github.com/opencloud-eu/opencloud/pull/3223)]
- build(deps): bump github.com/open-policy-agent/opa from 1.18.2 to 1.19.0 [[#3231](https://github.com/opencloud-eu/opencloud/pull/3231)]
- build(deps): bump google.golang.org/grpc from 1.82.0 to 1.83.0 [[#3232](https://github.com/opencloud-eu/opencloud/pull/3232)]
- chore(idp): bump dependencies [[#3226](https://github.com/opencloud-eu/opencloud/pull/3226)]
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.14.3 to 2.14.4 [[#3221](https://github.com/opencloud-eu/opencloud/pull/3221)]
- build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.13 to 3.4.14 [[#3222](https://github.com/opencloud-eu/opencloud/pull/3222)]
- build(deps): bump github.com/prometheus/client_golang from 1.23.2 to 1.24.1 [[#3218](https://github.com/opencloud-eu/opencloud/pull/3218)]
- build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.13 to 1.4.15 [[#3217](https://github.com/opencloud-eu/opencloud/pull/3217)]
- build(deps): bump golang.org/x/net from 0.56.0 to 0.57.0 [[#3136](https://github.com/opencloud-eu/opencloud/pull/3136)]
- build(deps): bump github.com/beevik/etree from 1.6.0 to 1.7.0 [[#3134](https://github.com/opencloud-eu/opencloud/pull/3134)]
## [7.3.0](https://github.com/opencloud-eu/opencloud/releases/tag/v7.3.0) - 2026-07-14
### 🐛 Bug Fixes
+21 -3
View File
@@ -68,8 +68,11 @@ OC_MODULES = \
protogen
# bin file definitions
PHP_CODESNIFFER=vendor-bin/opencloud-codestyle/vendor/bin/phpcs
PHP_CODEBEAUTIFIER=vendor-bin/opencloud-codestyle/vendor/bin/phpcbf
PHP_CS_FIXER=php -d zend.enable_gc=0 vendor-bin/opencloud-codestyle/vendor/bin/php-cs-fixer
PHP_CODESNIFFER=vendor-bin/php_codesniffer/vendor/bin/phpcs
PHP_CODEBEAUTIFIER=vendor-bin/php_codesniffer/vendor/bin/phpcbf
PHAN=php -d zend.enable_gc=0 vendor-bin/phan/vendor/bin/phan
PHPSTAN=php -d zend.enable_gc=0 vendor-bin/phpstan/vendor/bin/phpstan
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
include .bingo/Variables.mk
@@ -316,15 +319,30 @@ ci-format: $(BUILDIFIER)
$(BUILDIFIER) --mode=fix .woodpecker.star
.PHONY: test-php-style
test-php-style: vendor-bin/opencloud-codestyle/vendor
test-php-style: vendor-bin/opencloud-codestyle/vendor vendor-bin/php_codesniffer/vendor
$(PHP_CS_FIXER) fix -v --diff --allow-risky yes --dry-run
$(PHP_CODESNIFFER) --cache --runtime-set ignore_warnings_on_exit --standard=phpcs.xml tests/acceptance tests/acceptance/TestHelpers
.PHONY: test-php-style-fix
test-php-style-fix: vendor-bin/opencloud-codestyle/vendor
$(PHP_CS_FIXER) fix -v --diff --allow-risky yes
$(PHP_CODEBEAUTIFIER) --cache --runtime-set ignore_warnings_on_exit --standard=phpcs.xml tests/acceptance
.PHONY: vendor-bin-codestyle
vendor-bin-codestyle: vendor-bin/opencloud-codestyle/vendor
.PHONY: vendor-bin-codesniffer
vendor-bin-codesniffer: vendor-bin/php_codesniffer/vendor
vendor-bin/opencloud-codestyle/vendor: vendor/bamarni/composer-bin-plugin vendor-bin/opencloud-codestyle/composer.lock
composer bin opencloud-codestyle install --no-progress
vendor-bin/opencloud-codestyle/composer.lock: vendor-bin/opencloud-codestyle/composer.json
@echo opencloud-codestyle composer.lock is not up to date.
vendor-bin/php_codesniffer/vendor: vendor/bamarni/composer-bin-plugin vendor-bin/php_codesniffer/composer.lock
composer bin php_codesniffer install --no-progress
vendor-bin/php_codesniffer/composer.lock: vendor-bin/php_codesniffer/composer.json
@echo php_codesniffer composer.lock is not up to date.
+62
View File
@@ -0,0 +1,62 @@
# Table of Contents
{{ range . -}}
* [Changelog for {{ .Version }}](#changelog-for-{{ .Version | replace "." ""}}-{{ .Date | lower -}})
{{ end -}}
{{ $allVersions := . }}
{{- range $index, $changes := . }}{{ with $changes -}}
{{ if gt (len $allVersions) 1 }}
# Changelog for [{{ .Version }}] ({{ .Date }})
The following sections list the changes for {{ .Version}}.
{{/* creating version compare links */ -}}
{{ $next := add1 $index -}}
{{ if ne (len $allVersions) $next -}}
{{ $previousVersion := (index $allVersions $next).Version -}}
{{ if eq .Version "unreleased" -}}
[{{ .Version}}]: https://github.com/opencloud-eu/opencloud/compare/v{{ $previousVersion }}...master
{{ else -}}
[{{ .Version}}]: https://github.com/opencloud-eu/opencloud/compare/v{{ $previousVersion }}...v{{ .Version}}
{{ end -}}
{{ end -}}
{{- /* last version managed by calens, end of the loop */ -}}
{{ if eq .Version "0.1.0" -}}
[{{ .Version }}]: https://github.com/opencloud-eu/opencloud/compare/94f19e653e30cdf16dcf23dbaf36c6d753d37ae9...v{{ .Version }}
{{ end -}}
{{ else -}}
# Changes in {{ .Version}}
{{ end -}}
## Summary
{{ range $entry := .Entries }}{{ with $entry }}
* {{ .Type }} - {{ .Title }}: [#{{ .PrimaryID }}]({{ .PrimaryURL }})
{{- end }}{{ end }}
## Details
{{ range $entry := .Entries }}{{ with $entry }}
* {{ .Type }} - {{ .Title }}: [#{{ .PrimaryID }}]({{ .PrimaryURL }})
{{ range $par := .Paragraphs -}}
{{/* Workaround for keeping lists inside of changelog items well formatted */ -}}
{{ if hasPrefix "*" $par }}
{{ $par | replace " *" "\n *" }}
{{- else }}
{{ wrapIndent $par 80 3 -}}
{{ end }}
{{ end -}}
{{ range $url := .IssueURLs }}
{{ $url -}}
{{ end -}}
{{ range $url := .PRURLs }}
{{ $url -}}
{{ end -}}
{{ range $url := .OtherURLs }}
{{ $url -}}
{{ end }}
{{ end }}{{ end -}}
{{ end }}{{ end -}}
+16
View File
@@ -0,0 +1,16 @@
# Changelog
We are using [calens](https://github.com/restic/calens) to properly generate a
changelog before we are tagging a new release. To get an idea how this could
look like <https://github.com/restic/restic/tree/master/changelog> would be the
best reference.
## Create changelog items
Create a file according to the template for each changelog in the unreleased folder.
The following change types are possible:
- Bugfix (general Bugfix)
- Enhancement (new feature)
- Change (breaking change)
- Security (security related issues)
+15
View File
@@ -0,0 +1,15 @@
Bugfix: Fix behavior for foobar (in present tense)
We've fixed the behavior for foobar, a long-standing annoyance for users. The
text should be wrapped at 80 characters length.
The text in the paragraphs is written in past tense. The last section is a list
of issue URLs, PR URLs and other URLs. The first issue ID (or the first PR ID,
in case there aren't any issue links) is used as the primary ID.
https://github.com/opencloud-eu/opencloud/pull/55555
https://github.com/opencloud-eu/opencloud/issues/1234
Note: Possible keywords are Bugfixes (for bug fixes), Enhancement (for new features),
Change (for breaking changes), Security (for security related topics)
+8
View File
@@ -0,0 +1,8 @@
## Release, Date, Type, Title, Primary ID, Primary URL
{{ range . -}}
{{ $v := .Version -}}
{{ $d := .Date -}}
{{ range $entry := .Entries -}}
{{ $v }},{{ $d }},{{ .Type }},'{{ .Title }}',{{ .PrimaryID }},{{ .PrimaryURL }}
{{ end -}}
{{ end -}}
View File
Whitespace-only changes.
@@ -0,0 +1,7 @@
Enhancement: Add WAYF configuration for reva OCM service
Add WAYF configuration support for the Reva OCM service,
enabling federation discovery functionality for Open Cloud Mesh.
This includes configuration for federations file storage and invite accept dialog URL.
https://github.com/opencloud-eu/opencloud/pull/1714
@@ -0,0 +1,9 @@
Bugfix: Don't re-escape notification email vars for each recipient
When a notification went to several recipients in one call (e.g. a group
invite to a space), each recipient past the first got subjects and bodies
with one extra layer of HTML escaping. escapeStringMap mutated its input
map, and the recipient loop reused the same map across iterations. It now
returns a new map.
https://github.com/opencloud-eu/opencloud/issues/2804
@@ -1,21 +0,0 @@
Bugfix: Retry publishing postprocessing events before giving up
A single transient failure while publishing an event to the event system took
the whole server down. The postprocessing service treated every publish error
as fatal and called log.Fatal, which exits the process and so also stopped all
the other services running in the same binary. A burst of uploads was enough to
run into one nats publish timeout and lose the server with it.
Publishing is now retried using the same exponential backoff that is already
used for failed postprocessing steps. Between the attempts the source event is
marked as in progress and the backoff is capped at half the ack wait, so the
event should not be redelivered to another worker while we are still retrying.
The number of retries is configurable via POSTPROCESSING_PUBLISH_MAX_RETRIES.
Should all attempts fail, the source event is no longer acknowledged. Before,
the event was acknowledged even though its successor was never published, so
the upload was left half processed in the store and did not recover on restart.
https://github.com/opencloud-eu/opencloud/issues/3271
https://github.com/opencloud-eu/opencloud/issues/2232
https://github.com/opencloud-eu/opencloud/issues/2422
+3 -4
View File
@@ -2,7 +2,7 @@
"name": "opencloud-eu/opencloud",
"config": {
"platform": {
"php": "8.4"
"php": "8.3"
},
"vendor-dir": "./vendor-php",
"allow-plugins": {
@@ -11,12 +11,11 @@
},
"require-dev": {
"ext-simplexml": "*",
"bamarni/composer-bin-plugin": "^1.9"
"bamarni/composer-bin-plugin": "^1.8"
},
"extra": {
"bamarni-bin": {
"bin-links": false,
"forward-command": false
"bin-links": false
}
}
}
@@ -45,4 +45,3 @@ directives:
style-src:
- '''self'''
- '''unsafe-inline'''
- 'blob:'
@@ -42,4 +42,3 @@ directives:
style-src:
- '''self'''
- '''unsafe-inline'''
- 'blob:'
+66 -65
View File
@@ -10,7 +10,7 @@ require (
github.com/MicahParks/keyfunc/v2 v2.1.0
github.com/Nerzal/gocloak/v13 v13.9.0
github.com/bbalet/stopwords v1.0.0
github.com/beevik/etree v1.7.1
github.com/beevik/etree v1.6.0
github.com/blevesearch/bleve/v2 v2.6.0
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.20.0
@@ -18,12 +18,12 @@ require (
github.com/davidbyttow/govips/v2 v2.18.0
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/gabriel-vasile/mimetype v1.4.15
github.com/gabriel-vasile/mimetype v1.4.13
github.com/ggwhite/go-masker v1.1.0
github.com/go-chi/chi/v5 v5.3.2
github.com/go-chi/chi/v5 v5.3.1
github.com/go-chi/render v1.0.3
github.com/go-jose/go-jose/v3 v3.0.5
github.com/go-ldap/ldap/v3 v3.4.14
github.com/go-ldap/ldap/v3 v3.4.13
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
github.com/go-micro/plugins/v4/client/grpc v1.2.1
github.com/go-micro/plugins/v4/logger/zerolog v1.2.0
@@ -43,48 +43,48 @@ require (
github.com/google/uuid v1.6.0
github.com/gookit/config/v2 v2.2.9
github.com/gorilla/mux v1.8.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
github.com/invopop/validation v0.8.0
github.com/jellydator/ttlcache/v2 v2.11.1
github.com/jellydator/ttlcache/v3 v3.4.1
github.com/jinzhu/now v1.1.5
github.com/justinas/alice v1.2.0
github.com/kovidgoyal/imaging v1.8.23
github.com/kovidgoyal/imaging v1.8.22
github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69
github.com/libregraph/idm v0.5.0
github.com/libregraph/lico v0.67.0
github.com/mna/pigeon v1.3.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/nats-io/nats-server/v2 v2.14.5
github.com/nats-io/nats-server/v2 v2.14.3
github.com/nats-io/nats.go v1.52.0
github.com/olekukonko/tablewriter v1.1.4
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.32.1
github.com/onsi/ginkgo/v2 v2.32.0
github.com/onsi/gomega v1.42.1
github.com/open-policy-agent/opa v1.19.0
github.com/open-policy-agent/opa v1.18.2
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260818063016-69f82a7dde55
github.com/opencloud-eu/reva/v2 v2.49.0
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d
github.com/opencloud-eu/reva/v2 v2.47.0
github.com/opensearch-project/opensearch-go/v4 v4.6.0
github.com/orcaman/concurrent-map v1.0.0
github.com/pkg/errors v0.9.1
github.com/pkg/xattr v0.4.12
github.com/prometheus/client_golang v1.24.1
github.com/prometheus/client_golang v1.23.2
github.com/r3labs/sse/v2 v2.10.0
github.com/riandyrn/otelchi v0.12.3
github.com/rogpeppe/go-internal v1.16.0
github.com/rogpeppe/go-internal v1.15.0
github.com/rs/cors v1.11.1
github.com/rs/zerolog v1.35.1
github.com/shamaton/msgpack/v2 v2.4.1
github.com/sirupsen/logrus v1.10.0
github.com/sirupsen/logrus v1.9.4
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.12.1
github.com/stretchr/testify v1.11.1
github.com/test-go/testify v1.1.4
github.com/testcontainers/testcontainers-go v0.44.0
github.com/testcontainers/testcontainers-go/modules/opensearch v0.44.0
github.com/testcontainers/testcontainers-go v0.43.0
github.com/testcontainers/testcontainers-go/modules/opensearch v0.43.0
github.com/theckman/yacspin v0.13.12
github.com/thejerf/suture/v4 v4.0.6
github.com/tidwall/gjson v1.19.0
github.com/tidwall/sjson v1.2.5
@@ -94,25 +94,25 @@ require (
github.com/xhit/go-simple-mail/v2 v2.16.0
go-micro.dev/v4 v4.11.0
go.etcd.io/bbolt v1.5.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0
go.opentelemetry.io/contrib/zpages v0.70.0
go.opentelemetry.io/otel v1.45.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0
go.opentelemetry.io/otel/sdk v1.45.0
go.opentelemetry.io/otel/trace v1.45.0
golang.org/x/crypto v0.55.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0
go.opentelemetry.io/contrib/zpages v0.69.0
go.opentelemetry.io/otel v1.44.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.44.0
go.opentelemetry.io/otel/sdk v1.44.0
go.opentelemetry.io/otel/trace v1.44.0
golang.org/x/crypto v0.53.0
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
golang.org/x/image v0.45.0
golang.org/x/net v0.58.0
golang.org/x/image v0.44.0
golang.org/x/net v0.56.0
golang.org/x/oauth2 v0.36.0
golang.org/x/sync v0.22.0
golang.org/x/term v0.45.0
golang.org/x/text v0.41.0
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d
google.golang.org/grpc v1.83.1
google.golang.org/protobuf v1.36.12
golang.org/x/text v0.40.0
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa
google.golang.org/grpc v1.82.0
google.golang.org/protobuf v1.36.11
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.5.2
@@ -135,7 +135,7 @@ require (
github.com/ajg/form v1.5.1 // indirect
github.com/alexedwards/argon2id v1.0.0 // indirect
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 // indirect
github.com/antithesishq/antithesis-sdk-go v0.7.2 // indirect
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -190,32 +190,32 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/dlclark/regexp2 v1.12.0 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/purego v0.10.1 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/emvi/iso-639-1 v1.1.1 // indirect
github.com/evanphx/json-patch/v5 v5.5.0 // indirect
github.com/fatih/color v1.19.0 // indirect
github.com/felixge/httpsnoop v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/gdexlab/go-render v1.0.1 // indirect
github.com/go-acme/lego/v4 v4.4.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.9.0 // indirect
github.com/go-git/go-git/v5 v5.19.2 // indirect
github.com/go-git/go-git/v5 v5.19.1 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-micro/plugins/v4/events/natsjs v1.2.2 // indirect
github.com/go-micro/plugins/v4/store/nats-js v1.2.1 // indirect
github.com/go-micro/plugins/v4/store/redis v1.2.1 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
@@ -255,7 +255,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/juliangruber/go-intersect v1.1.0 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.19.2 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/klauspost/crc32 v1.3.0 // indirect
github.com/kovidgoyal/go-parallel v1.1.1 // indirect
@@ -271,13 +271,13 @@ require (
github.com/libregraph/oidc-go v1.1.0 // indirect
github.com/longsleep/go-metrics v1.0.0 // indirect
github.com/longsleep/rndm v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.15 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/mattn/go-runewidth v0.0.24 // indirect
github.com/mattn/go-sqlite3 v1.14.49 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.23 // indirect
github.com/mattn/go-sqlite3 v1.14.42 // indirect
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b // indirect
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect
github.com/miekg/dns v1.1.68 // indirect
@@ -290,10 +290,10 @@ require (
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.2.0 // indirect
github.com/moby/moby/api v1.55.0 // indirect
github.com/moby/moby/client v0.5.0 // indirect
github.com/moby/moby/api v1.54.2 // indirect
github.com/moby/moby/client v0.4.0 // indirect
github.com/moby/patternmatcher v0.6.1 // indirect
github.com/moby/sys/sequential v0.7.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
@@ -325,8 +325,8 @@ require (
github.com/pquerna/cachecontrol v0.2.0 // indirect
github.com/prometheus/alertmanager v0.33.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.70.1 // indirect
github.com/prometheus/procfs v0.21.1 // indirect
github.com/prometheus/common v0.67.5 // indirect
github.com/prometheus/procfs v0.20.1 // indirect
github.com/prometheus/statsd_exporter v0.22.8 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/rs/xid v1.6.0 // indirect
@@ -342,9 +342,10 @@ require (
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/sercand/kuberesolver/v5 v5.1.1 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/sethvargo/go-diceware v0.6.0 // indirect
github.com/sethvargo/go-password v0.4.0 // indirect
github.com/shirou/gopsutil/v4 v4.26.6 // indirect
github.com/sethvargo/go-diceware v0.5.0 // indirect
github.com/sethvargo/go-password v0.3.1 // indirect
github.com/shamaton/msgpack/v2 v2.4.1 // indirect
github.com/shirou/gopsutil/v4 v4.26.5 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
@@ -356,13 +357,13 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tinylib/msgp v1.6.1 // indirect
github.com/tklauser/go-sysconf v0.4.0 // indirect
github.com/tklauser/numcpus v0.12.0 // indirect
github.com/tklauser/go-sysconf v0.3.16 // indirect
github.com/tklauser/numcpus v0.11.0 // indirect
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
github.com/trustelem/zxcvbn v1.0.1 // indirect
github.com/urfave/cli/v2 v2.27.7 // indirect
github.com/valyala/fastjson v1.6.10 // indirect
github.com/vektah/gqlparser/v2 v2.5.36 // indirect
github.com/vektah/gqlparser/v2 v2.5.34 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/wk8/go-ordered-map v1.0.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
@@ -377,19 +378,19 @@ require (
go.etcd.io/etcd/client/v3 v3.6.13 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 // indirect
go.opentelemetry.io/otel/metric v1.45.0 // indirect
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
go.opentelemetry.io/otel/metric v1.44.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/mod v0.38.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.37.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.48.0 // indirect
golang.org/x/tools v0.47.0 // indirect
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/ini.v1 v1.67.3 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
+134 -135
View File
@@ -115,8 +115,8 @@ github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antithesishq/antithesis-sdk-go v0.7.2 h1:oEEedg1Xgi8drRjqB0f9tfjhLoInE0IYZfZ6zAhQUbY=
github.com/antithesishq/antithesis-sdk-go v0.7.2/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
@@ -132,8 +132,8 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W
github.com/aws/aws-sdk-go v1.37.27/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/bbalet/stopwords v1.0.0 h1:0TnGycCtY0zZi4ltKoOGRFIlZHv0WqpoIGUsObjztfo=
github.com/bbalet/stopwords v1.0.0/go.mod h1:sAWrQoDMfqARGIn4s6dp7OW7ISrshUD8IP2q3KoqPjc=
github.com/beevik/etree v1.7.1 h1:xBlSFAjlMfZkrCNKCEdZ2MSN9pfQYeRBaISDnAVi4Ek=
github.com/beevik/etree v1.7.1/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc=
github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE=
github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -195,6 +195,8 @@ github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 h1:h8Z0hBv5tg/uZMKu8V47+DKWYVQg0lYP8lXDQq7uRpE=
github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3/go.mod h1:eE/tD53n3KbVrzrWxKLxdkGw45Fg1qaNLWjpJMvIUF4=
github.com/bytecodealliance/wasmtime-go/v44 v44.0.0 h1:WRZXnLPIer/TWs5aYPaMlmVcOlzmR6Ur6wjLRIQOhTQ=
github.com/bytecodealliance/wasmtime-go/v44 v44.0.0/go.mod h1:GP93piU+39CoFVCQ5xfHrPOUtL0APlMnkbblJ2d3YY0=
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -279,8 +281,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjY
github.com/deepmap/oapi-codegen v1.3.11/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0=
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
github.com/dgraph-io/badger/v4 v4.9.4 h1:bcw+waCpzRZ2nmcSPbnPvDVhiEsn98TKmvnAhK7r7LM=
github.com/dgraph-io/badger/v4 v4.9.4/go.mod h1:nJjaJTUOSsQEBhsq209FmwCvMJzEA3e74RjZw6V2pQI=
github.com/dgraph-io/badger/v4 v4.9.2 h1:Wb5qw8gElqwV1a8msHTeQKova9b1V10heFKMIiPd80E=
github.com/dgraph-io/badger/v4 v4.9.2/go.mod h1:nJjaJTUOSsQEBhsq209FmwCvMJzEA3e74RjZw6V2pQI=
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM=
@@ -302,8 +304,8 @@ github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -313,8 +315,8 @@ github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e/go.mod h1:Byz
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY=
github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc h1:6IxmRbXV8WXVkcYcTzkU219A3UZeNMX/e6X2sve1wXA=
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc/go.mod h1:FdVN2WHg7zOHhJ7kZQdDorfFhIfqZaHttjAzDDvAXHE=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
@@ -336,8 +338,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/foxcpp/go-mockdns v1.2.0 h1:omK3OrHRD1IWJz1FuFBCFquhXslXoF17OvBS6JPzZF0=
@@ -348,8 +350,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/gabriel-vasile/mimetype v1.4.15 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI=
github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
@@ -368,11 +370,11 @@ github.com/go-acme/lego/v4 v4.4.0 h1:uHhU5LpOYQOdp3aDU+XY2bajseu8fuExphTL1Ss6/Fc
github.com/go-acme/lego/v4 v4.4.0/go.mod h1:l3+tFUFZb590dWcqhWZegynUthtaHJbG2fevUpoOOE0=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.8 h1:H9AZkK22UOmfX8J84ubyaZxKJZ3FMHVwn8swoMML7iQ=
github.com/go-asn1-ber/asn1-ber v1.5.8/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
@@ -383,8 +385,8 @@ github.com/go-git/go-billy/v5 v5.9.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmm
github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.19.2 h1:wkfn7vOlUBu8ivAWKBWisTiwJK4jYHzTF8Ndv1LyGqY=
github.com/go-git/go-git/v5 v5.19.2/go.mod h1:QqCBE1EFN5ddFmrliLQ3/ntRCUjZU3EJuwuB/jWEHjk=
github.com/go-git/go-git/v5 v5.19.1 h1:nX27AnaU43/K5bKktKwgBmR9lawoYVe1Ckg0rgzzN00=
github.com/go-git/go-git/v5 v5.19.1/go.mod h1:Pb1v0c7/g8aGQJwx9Us09W85yGoyvSwuhEGMH7zjDKQ=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -400,8 +402,8 @@ github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-ldap/ldap/v3 v3.4.14 h1:D6PYdEgsaVzsXyr6w/yDC06Ria4uUhWm+Rb+er8lfAs=
github.com/go-ldap/ldap/v3 v3.4.14/go.mod h1:S4eJUMUNjDkE0ZJtIZdybwyb03sGGLW6gxXT1Hs8VKA=
github.com/go-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ=
github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0=
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 h1:sfz1YppV05y4sYaW7kXZtrocU/+vimnIWt4cxAYh7+o=
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3/go.mod h1:ZXFhGda43Z2TVbfGZefXyMJzsDHhCh0go3bZUcwTx7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -410,8 +412,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-micro/plugins/v4/client/grpc v1.2.1 h1:7xAwZRCO6mdUtBHsYIQs1/eCTdhCrnjF70GB+AVd6L0=
@@ -436,9 +438,8 @@ github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus v1.2.0 h1:UWBUYtMXC
github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus v1.2.0/go.mod h1:8BYxs/wEE4ZJayHZQffw4A8s9rcPumyoNms0hYoNocM=
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0 h1:e2hgtWMNqJ3DmbMt9ZxzmH/BkVAw9Xg23l6CHrXQfKw=
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0/go.mod h1:BBqL7ckGNb7rFfk3vU2Yj/CILVsz/WF19CkAyveQl8A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -548,6 +549,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
@@ -607,8 +609,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vb
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -713,8 +715,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
@@ -730,8 +732,8 @@ github.com/kovidgoyal/go-parallel v1.1.1 h1:1OzpNjtrUkBPq3UaqrnvOoB2F9RttSt811ui
github.com/kovidgoyal/go-parallel v1.1.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw=
github.com/kovidgoyal/go-shm v1.0.0 h1:HJEel9D1F9YhULvClEHJLawoRSj/1u/EDV7MJbBPgQo=
github.com/kovidgoyal/go-shm v1.0.0/go.mod h1:Yzb80Xf9L3kaoB2RGok9hHwMIt7Oif61kT6t3+VnZds=
github.com/kovidgoyal/imaging v1.8.23 h1:4WsboyQ/E8tic2kX49P93Rvscg33SPsCwTBG5EZZF54=
github.com/kovidgoyal/imaging v1.8.23/go.mod h1:k3Iot3H0v2rSWXIxQISfT3e9wIryqzAHLHCuhG7z9lM=
github.com/kovidgoyal/imaging v1.8.22 h1:CtpoRXQpS79xxJsKu8+LUJJE/0i4FLquJZy0QH+QNlM=
github.com/kovidgoyal/imaging v1.8.22/go.mod h1:y8wo4JTv4D+skbtQf6fHg8nA1qtagvCcn8J2Nu5k2Jg=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -781,8 +783,8 @@ github.com/longsleep/go-metrics v1.0.0 h1:o2A6Dbu4MhLpZuL444WFoZzM7X7igewrj2Mouw
github.com/longsleep/go-metrics v1.0.0/go.mod h1:w6QO1LBkVla70FZrrF6XcB0YN+jTEYugjkn3+6RYTSM=
github.com/longsleep/rndm v1.2.0 h1:wPl+kIMyIUTUFW5+2b327DmM1Rlj+gmexsiyOTB7rzM=
github.com/longsleep/rndm v1.2.0/go.mod h1:5qyvM6CXNteKgz6djqqwZOP4+KcPsewrfKyLWd1dCFY=
github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak=
github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
@@ -799,23 +801,23 @@ github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-sqlite3 v1.14.49 h1:B8jBHC3xhxZgxztrgruTuLucebnULQnx4W7cF7SAE9w=
github.com/mattn/go-sqlite3 v1.14.49/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo=
github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -859,14 +861,14 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc=
github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/moby/moby/client v0.5.0 h1:5XhyPk2fuOWf6RlSFa3MkIIgDZkF25xToXW8Q/BH7cc=
github.com/moby/moby/client v0.5.0/go.mod h1:rcVpF8ncl9vo5gaIBdol6CnbEtSj1uxMvEV/UrykF/s=
github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg=
github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjIw=
github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8=
github.com/moby/sys/sequential v0.7.0/go.mod h1:NfSTAp6V3fw4tmkD62PEcOKeZKquXT8VKCkf7aVR79o=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
@@ -892,8 +894,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
github.com/nats-io/jwt/v2 v2.8.2 h1:XXRgB60MSTnqsRwejQurVDs/hcv2dkt+86GjI+I/bMc=
github.com/nats-io/jwt/v2 v2.8.2/go.mod h1:Ag/56sq9OblL4JgdYufDd16Egb17Kr/8WwwuO/forVc=
github.com/nats-io/nats-server/v2 v2.14.5 h1:M6yeo/Xb7khi97RSEVELof3DForDqmYza3P4tHCPFWw=
github.com/nats-io/nats-server/v2 v2.14.5/go.mod h1:1D3iocrisKvWaD1B/imqarTqmaGrWMqALMLbEDo3v7Q=
github.com/nats-io/nats-server/v2 v2.14.3 h1:+xjydPt7rkit67G+04TN0mcO2n+8nveZE7tK/PPV53A=
github.com/nats-io/nats-server/v2 v2.14.3/go.mod h1:5IlCtBzfwyzQzPMjmoJ9W2/LKmnJRtNyuOs/OT+NHDY=
github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc=
github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=
@@ -927,23 +929,23 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.32.1 h1:6tlvcDm/3sE8lGJbZ4+d4mO3RLy24/tQWOFzVSQNIfw=
github.com/onsi/ginkgo/v2 v2.32.1/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
github.com/onsi/ginkgo/v2 v2.32.0 h1:Hw7s2pVrQo/8Yz5N77qdnpHaoc+c6cC9WIV1Jce+J6E=
github.com/onsi/ginkgo/v2 v2.32.0/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.42.1 h1:iN1rCUX+44NZ1Dc97MPoeFYbFR0vh8zxoxMFwKdyZ6I=
github.com/onsi/gomega v1.42.1/go.mod h1:REff/hsDsodHoKlWsP2mAPhu1+5/6hVYNf9rIEBpeSg=
github.com/open-policy-agent/opa v1.19.0 h1:+j2OCsjMezZEML2T1lI9giJdGJS/PL1XFKgkHPGIhpo=
github.com/open-policy-agent/opa v1.19.0/go.mod h1:pb6Y6klyf7X7X8uXNDflruA9dQC2gMqWROXI5w/kvv0=
github.com/open-policy-agent/opa v1.18.2 h1:VBiLJpioTuk7XTW1JoQi4ILo+FVxD2/8uD8iP9/OcxY=
github.com/open-policy-agent/opa v1.18.2/go.mod h1:9GY+hER4ZEXtxPlMjftVbqJJY9xLtCD3Q0oufRCfAKo=
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+lP5lUUIzjRGDg93WrQfZJZCaV1ZP3KeyXi8bzY=
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260818063016-69f82a7dde55 h1:dzYZ5iA6i0QoFUap9l6sZ4Ts2HXiXVfsOoiRYToYgm8=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260818063016-69f82a7dde55/go.mod h1:lTM8JeGblNpoMySTW7Lui2+c5TTLI95mwxtdUIHHrhU=
github.com/opencloud-eu/reva/v2 v2.49.0 h1:AwECMDDth3NUaihZRf9bI9HNpWutvaRijOCvQyQfTT4=
github.com/opencloud-eu/reva/v2 v2.49.0/go.mod h1:Frg+UWnVcSy+412UB3l2LcD0KY8ZNu1samimwkNywbg=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d h1:JcqGDiyrcaQwVyV861TUyQgO7uEmsjkhfm7aQd84dOw=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
github.com/opencloud-eu/reva/v2 v2.47.0 h1:bYul45qS8GmmN9PKplSZ78ZTZ6A+9xp/FfogqFVud18=
github.com/opencloud-eu/reva/v2 v2.47.0/go.mod h1:zdpEKIMDT14w+MGUOWAi+rh+PAZBPUlb7AtIGFWx7Ds=
github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 h1:l2oB/RctH+t8r7QBj5p8thfEHCM/jF35aAY3WQ3hADI=
github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
@@ -1014,8 +1016,8 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU=
github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -1035,8 +1037,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi/PY=
github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.0.0-20170703101242-e645f4e5aaa8/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -1047,8 +1049,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
github.com/prometheus/statsd_exporter v0.22.8 h1:Qo2D9ZzaQG+id9i5NYNGmbf1aa/KxKbB9aKfMS+Yib0=
github.com/prometheus/statsd_exporter v0.22.8/go.mod h1:/DzwbTEaFTE0Ojz5PqcSk6+PFHOPWGxdXVr6yC8eFOM=
@@ -1063,8 +1065,8 @@ github.com/riandyrn/otelchi v0.12.3 h1:KW9gA+97d6mExk8vbh0FRwb2biUvpyYlc8YuxP1Oa
github.com/riandyrn/otelchi v0.12.3/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g=
github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc=
github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
@@ -1100,23 +1102,23 @@ github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aep
github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/sethvargo/go-diceware v0.6.0 h1:B3nhMhbBP7KwtTQ7hHRIOmv5FqeD8bJs77RFrV24iWk=
github.com/sethvargo/go-diceware v0.6.0/go.mod h1:lHmdB0xuWaJ06KCraW6bztRT+71Dp+lsXQvborhhsBc=
github.com/sethvargo/go-password v0.4.0 h1:eSidVKQw5C7CmTDAtH3RipBTSjdU1ZRxQaynD2GWLVU=
github.com/sethvargo/go-password v0.4.0/go.mod h1:PO3nYHwUpcHPR0F9woy7a4abZPvzRuqJr0GaeIYTm3k=
github.com/sethvargo/go-diceware v0.5.0 h1:exrQ7GpaBo00GqRVM1N8ChXSsi3oS7tjQiIehsD+yR0=
github.com/sethvargo/go-diceware v0.5.0/go.mod h1:Lg1SyPS7yQO6BBgTN5r4f2MUDkqGfLWsOjHPY0kA8iw=
github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU=
github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs=
github.com/shamaton/msgpack/v2 v2.4.1 h1:JtJ141QoQ3NqgPDsjq2v9VXlaON8SiQOwEaoNLEK/MQ=
github.com/shamaton/msgpack/v2 v2.4.1/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil/v4 v4.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs=
github.com/shirou/gopsutil/v4 v4.26.6/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM=
github.com/shirou/gopsutil/v4 v4.26.5/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.10.0 h1:T8MxJJXVZkfcC5zSRMRAg2F8+lxjmUCGGWPzFxO+Msc=
github.com/sirupsen/logrus v1.10.0/go.mod h1:FXZFonkDAnFozmO+5hGAFvB0Yg9/j2SIhA/QuIkP180=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
@@ -1173,9 +1175,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
@@ -1184,14 +1185,14 @@ github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhg
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
github.com/testcontainers/testcontainers-go v0.44.0 h1:/Fwh6HY1mIikhnm9e7HwoxGycx0lzRAE0f5VQpjFxzI=
github.com/testcontainers/testcontainers-go v0.44.0/go.mod h1:IcnwQrYTO86xHXu5bvMaBH7ATlbS3Qn1M1QWW3c66rE=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.44.0 h1:iuBDo8U8Nwt0z+bxEmU+c7jS9hw81nPL9uGkkFOcXTo=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.44.0/go.mod h1:8Qw29ffsCPzhomxqoeGhpj3J3Lbsrv0FsOUWeOjTl+I=
github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU=
github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0=
github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0eLs7ztyaGRu75bFo5A=
github.com/testcontainers/testcontainers-go v0.43.0/go.mod h1:+VxkT2NQnKOZPKi6praMuMKYHYyOGXr0XSBSlSMCzFo=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.43.0 h1:a1ipjF7d/VxPX1dgVPIk4F+t6YkgMbE2OtBuRQCHJt8=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.43.0/go.mod h1:OWSeUDiGMUy30iMsAltIJIo9uh/CleLv6KyxjYOsgR8=
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4=
github.com/theckman/yacspin v0.13.12/go.mod h1:Rd2+oG2LmQi5f3zC3yeZAOl245z8QOvrH4OPOJNZxLg=
github.com/thejerf/suture/v4 v4.0.6 h1:QsuCEsCqb03xF9tPAsWAj8QOAJBgQI1c0VqJNaingg8=
github.com/thejerf/suture/v4 v4.0.6/go.mod h1:gu9Y4dXNUWFrByqRt30Rm9/UZ0wzRSt9AJS6xu/ZGxU=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -1206,10 +1207,10 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY=
github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU=
github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI=
github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4=
github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg=
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
@@ -1228,8 +1229,8 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADT
github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/vektah/gqlparser/v2 v2.5.36 h1:CN9mKVHgMkc+XftdOWIhb4HEL8wKSYkFAqhf8booa7s=
github.com/vektah/gqlparser/v2 v2.5.36/go.mod h1:cAJ9qwVgPaUkWv6Gn8vn0mqOE0Ui5Pn56wNy5396XWo=
github.com/vektah/gqlparser/v2 v2.5.34 h1:MEea5P0qhdcqfBL45ghKE+qr9laidVHTMHjav5h7ckk=
github.com/vektah/gqlparser/v2 v2.5.34/go.mod h1:mFdHLGCio7OGX1fby9ZjTW6FN+qxgmbnBcRIeeScE5s=
github.com/vinyldns/go-vinyldns v0.0.0-20200917153823-148a5f6b8f14/go.mod h1:RWc47jtnVuQv6+lY3c768WtXCas/Xi+U5UFc5xULmYg=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
@@ -1293,30 +1294,30 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0 h1:oECp5f+hN7nkwjU/8BxQ/q23bGPb8FIrD839owX222E=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.70.0/go.mod h1:DqEFwLumhzMBDQv9PcWbyoDxHI/4lAk6CM4nJBH39sc=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0 h1:LMuyCAyfalSjDyjdC65nK6N0zoTT63+E/u95X0JovZI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.70.0/go.mod h1:085m8qbm4hgc8rZWGDEa4vmyyo2c3nPxUslYUKUIU04=
go.opentelemetry.io/contrib/zpages v0.70.0 h1:uBcclHekIrCRLO4KZfXiebDcWB52QQXaHGgvhUJ1K5I=
go.opentelemetry.io/contrib/zpages v0.70.0/go.mod h1:Nz9A1+68HVoJrk+cg92zJbcbHFAa+Jbl1uINwAlcK94=
go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU=
go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0 h1:lsA/S1bxgdbyFGkTj+3meEdJ6ADVU7QoFstV6MXgE68=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0/go.mod h1:L7u+MirGoB1bjeLH66+xDykF4RC8C3RN7lIFpBiewUo=
go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M=
go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s=
go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw=
go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA=
go.opentelemetry.io/otel/sdk/metric v1.45.0 h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o=
go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA=
go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag=
go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc=
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/contrib/zpages v0.69.0 h1:YQC1PumJq6lUGQNrLW14ID9a0dXSBcbC/aC6VRSIARU=
go.opentelemetry.io/contrib/zpages v0.69.0/go.mod h1:FGvUcMGN5atRzUIgUsqOi+MiMvlQsfbuYATBHPP4cGs=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.44.0 h1:bl2S7Ubua0Nms+D/gAmznQTd4dxxMA93aKbcpKqiTCs=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.44.0/go.mod h1:L0hRV50XdVIODHUfWEqGRCXQvj2rV82STVo12FMFBU0=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -1334,9 +1335,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1356,8 +1356,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1372,8 +1372,8 @@ golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJk
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.45.0 h1:FMb1nTbH5H9vF55SriQHgFw5GnNL9Jg6L25BwXKzhB0=
golang.org/x/image v0.45.0/go.mod h1:n62x/7RqlwXDvGsSU4u6IUTUf6KghUZ9Bt7cG/T9Fx4=
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1395,8 +1395,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1447,8 +1447,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1547,7 +1547,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1579,8 +1578,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1641,8 +1640,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1704,10 +1703,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I=
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc=
google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -1723,8 +1722,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y=
google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
google.golang.org/grpc v1.82.0 h1:vguDnZUPjE26w09A63VoxZPnvPjB5Riyc0mkXPFmAIU=
google.golang.org/grpc v1.82.0/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -1741,8 +1740,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
-133
View File
@@ -1,133 +0,0 @@
[tools]
go = "1.25"
node = "24"
pnpm = "11.1.3"
"go:github.com/go-delve/delve/cmd/dlv" = "1.27.0"
"aqua:nats-io/natscli" = "0.4.0"
[tasks.build]
description = "build"
run = "make -C opencloud build"
[tasks."build:debug"]
description = "build with debug symbols"
run = "make -C opencloud build-debug"
[tasks."docker:build"]
description = "docker image opencloudeu/opencloud:dev"
run = "make -C opencloud dev-docker"
[tasks."docker:build:multiarch"]
description = "docker image for amd64 + arm64"
depends = ["gen"]
run = "make -C opencloud dev-docker-multiarch"
[tasks."docker:build:debug"]
description = "docker image with delve"
run = "make -C opencloud debug-docker"
[tasks.serve]
description = "start the server"
depends = ["build"]
run = "opencloud/bin/opencloud server"
[tasks."serve:init"]
description = "create the local config"
depends = ["build"]
run = "opencloud/bin/opencloud init"
[tasks."serve:debug"]
description = "start the server under delve"
depends = ["build:debug"]
run = "dlv exec opencloud/bin/opencloud-debug -- server"
[tasks.test]
description = "go test"
run = "go test -tags disable_crypt ./..."
[tasks."test:changed"]
description = "go test, changed packages"
run = """
base=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo origin/main)
files=$(git diff --name-only --diff-filter=ACM $(git merge-base "$base" HEAD) -- '*.go' | grep -v vendor/ || true)
[ -n "$files" ] || exit 0
go test -tags disable_crypt $(echo "$files" | xargs -n1 dirname | sort -u | sed 's|^|./|')
"""
[tasks."test:race"]
description = "go test + race"
run = "go test -race -tags disable_crypt ./..."
[tasks."test:coverage"]
description = "go test + coverage"
run = ["make test", "make go-coverage"]
[tasks.check]
description = "all checks"
depends = ["check:fmt", "check:lint", "check:vendor", "check:env-vars", "test"]
[tasks."check:fmt"]
description = "gofmt"
run = """
base=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo origin/main)
files=$(git diff --name-only --diff-filter=ACM $(git merge-base "$base" HEAD) -- '*.go' | grep -v vendor/ || true)
[ -n "$files" ] || exit 0
out=$(gofmt -s -l $files)
[ -z "$out" ] || { echo "$out"; exit 1; }
"""
[tasks."check:lint"]
description = "golangci-lint"
run = """
set -e
base=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo origin/main)
gobin=$(go env GOBIN)
[ -n "$gobin" ] || gobin="$(go env GOPATH)/bin"
bin="$gobin/golangci-lint-$(awk '/golangci-lint v/ {print $3}' .bingo/golangci-lint.mod)"
[ -x "$bin" ] || make -s golangci-lint >/dev/null
exec "$bin" run --modules-download-mode vendor --timeout 15m0s --new-from-merge-base "$base"
"""
[tasks."check:vendor"]
description = "vendor matches go.mod"
run = "GOWORK=off go list -mod=vendor ./... >/dev/null"
[tasks."check:env-vars"]
description = "env var annotations"
run = "make check-env-var-annotations"
[tasks.fix]
description = "gofmt + lint fixes"
run = [{ task = "fix:fmt" }, { task = "fix:lint" }]
[tasks."fix:fmt"]
description = "gofmt -w"
run = """
base=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo origin/main)
files=$(git diff --name-only --diff-filter=ACM $(git merge-base "$base" HEAD) -- '*.go' | grep -v vendor/ || true)
[ -z "$files" ] || gofmt -s -w $files
"""
[tasks."fix:lint"]
description = "golangci-lint --fix"
run = "make golangci-lint-fix"
[tasks."pre:commit"]
description = "before commit"
run = [{ task = "fix:fmt" }, { task = "check:lint" }, { task = "test:changed" }]
[tasks."pre:push"]
description = "before push"
run = [{ task = "tidy" }, { task = "fix:fmt" }, { task = "check" }]
[tasks.gen]
description = "assets & mocks"
run = "make generate"
[tasks."gen:protobuf"]
description = "protobuf"
run = "make protobuf"
[tasks.tidy]
description = "tidy + vendor"
run = ["GOWORK=off go mod tidy", "GOWORK=off go mod vendor"]
+1 -4
View File
@@ -11,10 +11,7 @@ RUN --mount=type=bind,target=/build,rw \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache \
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
make -C ${SRCDIR:-.}/opencloud release-linux-docker-${TARGETARCH} \
ENABLE_VIPS=true DIST=/dist \
VERSION="${VERSION}" EDITION="${EDITION}" \
${STRING:+STRING="${STRING}"}
make -C ${SRCDIR:-.}/opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
FROM alpine:3.24
ARG VERSION
+432 -259
View File
@@ -1,16 +1,17 @@
package command
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
"github.com/opencloud-eu/opencloud/pkg/config"
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
"github.com/opencloud-eu/opencloud/pkg/config/parser"
"github.com/opencloud-eu/opencloud/pkg/x/path/filepathx"
storageUsersParser "github.com/opencloud-eu/opencloud/services/storage-users/pkg/config/parser"
"github.com/opencloud-eu/opencloud/services/storage-users/pkg/event"
"github.com/opencloud-eu/opencloud/services/storage-users/pkg/revaconfig"
@@ -18,10 +19,27 @@ import (
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore"
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options"
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/registry"
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
"github.com/pkg/xattr"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
"github.com/theckman/yacspin"
"github.com/vmihailenco/msgpack/v5"
)
// Define the names of the extended attributes we are working with.
const (
parentIDAttrName = "user.oc.parentid"
idAttrName = "user.oc.id"
nameAttrName = "user.oc.name"
spaceIDAttrName = "user.oc.space.id"
ownerIDAttrName = "user.oc.owner.id"
)
var (
spinner *yacspin.Spinner
restartRequired = false
ignorer *ignore.Ignorer
)
type IDCacher interface {
@@ -55,23 +73,11 @@ func init() {
// scanCmd performs a posixfs id cache warmup scan
func scanCmd(ocCfg *config.Config) *cobra.Command {
scanCmd := &cobra.Command{
Use: "scan [path ...]",
cmd := &cobra.Command{
Use: "scan",
Short: "Perform a filesystem scan and update the ID and filemetadata cache",
Long: `Perform a filesystem scan and update the ID and filemetadata cache.
You can specify one or more paths to limit the scope of the scan.
If no path is provided, the whole storage is checked, starting at the storage root directory.
The provided arguments determines the scope of the check:
- a storage root: the whole storage (all personal and project spaces) is scanned
- a space root: only that space is scanned
- a file or directory: only that single resource is scanned (and its children, if it is a directory)
Any specified file or directory must be underneath the storage root directory and if that is not the case,
the command is aborted with an error before performing any scanning.`,
Args: cobra.ArbitraryArgs,
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := parser.ParseConfig(ocCfg, true); err != nil {
return configlog.ReturnError(err)
}
@@ -88,281 +94,448 @@ the command is aborted with an error before performing any scanning.`,
os.Exit(1)
}
haltOnError, err := cmd.Flags().GetBool("halt-on-error")
// We want to initialize the driver but disable scanfs on boot, so we can trigger it manually afterwards
drivers := revaconfig.StorageProviderDrivers(cfg)
drivers["posix"] = revaconfig.Posix(cfg, false, false)
var fsStream events.Stream
var err error
fsStream, err = event.NewStream(cfg)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create event stream for posix driver: %v\n", err)
os.Exit(1)
}
f, ok := registry.NewFuncs["posix"]
if !ok {
fmt.Fprintf(os.Stderr, "posix driver not found in registry\n")
os.Exit(1)
}
fs, err := f(drivers["posix"].(map[string]any), fsStream, nil)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to initialize filesystem driver '%s': %v\n", cfg.Driver, err)
return err
}
storageRoot := cfg.Drivers.Posix.Root
paths := []string{storageRoot}
if len(args) > 0 {
paths = []string{}
for _, v := range args {
path := v
if !filepath.IsAbs(path) {
if v, err := filepath.Abs(path); err != nil {
fmt.Fprintf(os.Stderr, "Failed to make the specified path %q absolute: %v\n", v, err)
os.Exit(1)
} else {
path = v
}
}
// not ensuring whether the path is under the storage root here, will be done when iterating over them
path = filepath.Clean(path)
paths = append(paths, path)
}
cacher, ok := fs.(IDCacher)
if !ok {
fmt.Fprintf(os.Stderr, "The posix driver does not expose WarmupIDCache.\n")
os.Exit(1)
}
var scan func(path string) error = nil
{
// We want to initialize the driver but disable scanfs on boot, so we can trigger it manually afterwards
drivers := revaconfig.StorageProviderDrivers(cfg)
drivers["posix"] = revaconfig.Posix(cfg, false, false)
var fsStream events.Stream
var err error
fsStream, err = event.NewStream(cfg)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create event stream for posix driver: %v\n", err)
os.Exit(1)
}
log := logger("posixfs")
f, ok := registry.NewFuncs["posix"]
if !ok {
fmt.Fprintf(os.Stderr, "posix driver not found in registry\n")
os.Exit(1)
}
fs, err := f(drivers["posix"].(map[string]any), fsStream, &log)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to initialize filesystem driver '%s': %v\n", cfg.Driver, err)
return err
}
cacher, ok := fs.(IDCacher)
if !ok {
fmt.Fprintf(os.Stderr, "The posix driver does not expose WarmupIDCache.\n")
os.Exit(1)
}
scan = func(path string) error {
err := cacher.WarmupIDCache(path, true, false)
if err != nil {
logFailure("Error scanning path '%s': %v", path, err)
}
return err
}
fmt.Println("Starting posixfs scan...")
err = cacher.WarmupIDCache(cfg.Drivers.Posix.Root, true, false)
if err != nil {
fmt.Fprintf(os.Stderr, "Scan failed: %v\n", err)
return err
}
errors := processPosixFsResources(paths, !haltOnError,
func(path string) error {
fmt.Println("Scanning personal spaces...")
return scan(path)
},
func(path string) error {
fmt.Println("Scanning project spaces...")
return scan(path)
},
func(path string) error {
fmt.Printf("Scanning space '%s'...\n", path)
return scan(path)
},
func(path string) error {
fmt.Printf("Scanning '%s'...\n", path)
return scan(path)
},
)
if len(errors) == 0 {
fmt.Println("Scan completed successfully.")
return nil
} else {
plural := "s"
if len(errors) == 1 {
plural = ""
}
verb := "completed"
if haltOnError {
verb = "aborted"
}
return fmt.Errorf("scan %s with %d error%s", verb, len(errors), plural)
}
fmt.Println("Scan completed successfully.")
return nil
},
}
scanCmd.Flags().BoolP("halt-on-error", "E", false, "Halt at once when an error occurs when processing one of the paths (default behaviour is to keep going and attempt to process all paths).")
return scanCmd
return cmd
}
// consistencyCmd returns a command to check the consistency of the posixfs storage.
func consistencyCmd(ocCfg *config.Config) *cobra.Command {
func consistencyCmd(cfg *config.Config) *cobra.Command {
consCmd := &cobra.Command{
Use: "consistency [path ...]",
Short: "Check the consistency of the posixfs storage",
Long: `Check the consistency of the posixfs storage.
You can specify one or more paths to limit the scope of the check.
If no path is provided, the whole storage is checked.
The provided arguments determines the scope of the check:
- a storage root: the whole storage (all personal and project spaces) is checked
- a space root: only that space is checked
- a file or directory: only that single entity is checked (and its children, if it is a directory)`,
Args: cobra.ArbitraryArgs,
PreRunE: func(cmd *cobra.Command, args []string) error {
if err := parser.ParseConfig(ocCfg, true); err != nil {
return configlog.ReturnError(err)
}
// Parse storage users config
ocCfg.StorageUsers.Commons = ocCfg.Commons
return configlog.ReturnFatal(storageUsersParser.ParseConfig(ocCfg.StorageUsers))
},
Use: "consistency",
Short: "check the consistency of the posixfs storage",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ocCfg.StorageUsers
if len(args) == 0 {
args = []string{cfg.Drivers.Posix.Root}
}
log := logger("posixfs")
recalculateChecksums, err := cmd.Flags().GetBool("fix-checksums")
if err != nil {
return err
}
drivers := revaconfig.StorageProviderDrivers(cfg)
drivers["posix"] = revaconfig.Posix(cfg, false, false)
opts, err := options.New(drivers["posix"].(map[string]any))
if err != nil {
return err
}
ignorer := ignore.NewIgnorer(opts, &log)
checker := &consistencyChecker{
cfg: cfg,
ignorer: ignorer,
recalculateChecksums: recalculateChecksums,
}
return checker.Check(args)
return checkPosixfsConsistency(cmd, cfg)
},
}
consCmd.Flags().Bool("fix-checksums", false, "Recalculate and fix the file checksums. This reads every file and can be slow on large storages.")
consCmd.Flags().StringP("root", "r", "", "Path to the root directory of the posixfs storage")
_ = consCmd.MarkFlagRequired("root")
return consCmd
}
func logFailure(message string, args ...any) {
fmt.Fprintf(os.Stderr, message+"\n", args...)
// checkPosixfsConsistency checks the consistency of the posixfs storage.
func checkPosixfsConsistency(cmd *cobra.Command, cfg *config.Config) error {
rootPath, _ := cmd.Flags().GetString("root")
indexesPath := filepath.Join(rootPath, "indexes")
opt, _ := options.New(map[string]interface{}{
"root": rootPath,
})
log := zerolog.Nop()
ignorer = ignore.NewIgnorer(opt, &log)
_, err := os.Stat(indexesPath)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("consistency check failed: '%s' is not a posixfs root", rootPath)
}
return fmt.Errorf("error accessing '%s': %w", indexesPath, err)
}
spinnerCfg := yacspin.Config{
Frequency: 100 * time.Millisecond,
CharSet: yacspin.CharSets[11],
StopCharacter: "✓",
StopColors: []string{"fgGreen"},
StopFailCharacter: "✗",
StopFailColors: []string{"fgRed"},
}
spinner, err = yacspin.New(spinnerCfg)
err = spinner.Start()
if err != nil {
return fmt.Errorf("error creating spinner: %w", err)
}
checkSpaces(filepath.Join(rootPath, "users"))
spinner.Suffix(" Personal spaces check ")
spinner.StopMessage("completed\n")
spinner.Stop()
checkSpaces(filepath.Join(rootPath, "projects"))
spinner.Suffix(" Project spaces check ")
spinner.StopMessage("completed")
spinner.Stop()
if restartRequired {
fmt.Println("\n\n ⚠️ Please restart your openCloud instance to apply changes.")
}
return nil
}
// findStorageRoot walks up the directory tree starting at path until it finds a
// directory that contains an "indexes" subdirectory which marks the root of a
// posixfs storage. A user directory inside a space might also be named "indexes",
// so to disambiguate we require that the "indexes" directory is an internal
// directory: the storage's own indexes directory is skipped during assimilation
// and therefore never receives a node ID attribute, whereas a regular user
// directory would have one.
func findStorageRoot(path string) (string, error) {
current := path
for {
indexesPath := filepath.Join(current, "indexes")
if info, err := os.Stat(indexesPath); err == nil && info.IsDir() {
if id, err := xattr.Get(indexesPath, prefixes.IDAttr); err != nil || len(id) == 0 {
return current, nil
}
}
func checkSpaces(basePath string) {
dirEntries, err := os.ReadDir(basePath)
if err != nil {
spinner.Message(fmt.Sprintf("Error reading spaces directory '%s'\n", basePath))
spinner.StopFail()
return
}
parent := filepath.Dir(current)
if parent == current {
return "", fmt.Errorf("'%s' does not appear to be inside a posixfs storage (no 'indexes' directory found)", path)
for _, entry := range dirEntries {
if entry.IsDir() {
fullPath := filepath.Join(basePath, entry.Name())
checkSpace(fullPath)
}
current = parent
}
}
// isSpaceRoot reports whether the given path is a space root, which is
// identified by the presence of the space ID attribute.
func isSpaceRoot(path string) bool {
spaceID, err := xattr.Get(path, prefixes.SpaceIDAttr)
return err == nil && len(spaceID) > 0
func checkSpace(spacePath string) {
spinner.Message("")
spinner.Suffix(fmt.Sprintf(" Checking space '%s'", spacePath))
info, err := os.Stat(spacePath)
if err != nil {
logFailure("Error accessing path '%s': %v", spacePath, err)
return
}
if !info.IsDir() {
logFailure("Error: The provided path '%s' is not a directory\n", spacePath)
return
}
spaceID, err := xattr.Get(spacePath, spaceIDAttrName)
if err != nil || len(spaceID) == 0 {
logFailure("Error: The directory '%s' does not seem to be a space root, it's missing the '%s' attribute\n", spacePath, spaceIDAttrName)
return
}
checkSpaceID(spacePath)
checkNodeIDs(spacePath)
}
// iterates over a list of paths and processes them all, using the appropriate function
// depending on the type of resource
//
// note that whenever an error occurs, it collects that error and continues processing
// subsequent paths, and then returns a slice of errors at the end (or an empty slice
// if no errors occured)
func processPosixFsResources(paths []string,
keepGoing bool,
personalSpaceDir func(string) error,
projectSpaceDir func(string) error,
spaceRoot func(string) error,
entity func(string) error,
) []error {
// no need to guard this with a mutex for now, since the implementation is not parallelized
errors := []error{}
func checkSpaceID(spacePath string) {
spinner.Message(" - checking space ID uniqueness")
for _, path := range paths {
rootPath, err := findStorageRoot(path)
entries, uniqueIDs, oldestEntry, err := gatherAttributes(spacePath)
if err != nil {
logFailure("Failed to gather attributes: %v", err)
return
}
if len(entries) == 0 {
return
}
if len(uniqueIDs) > 1 {
spinner.Pause()
fmt.Println("\n ⚠ Multiple space IDs found:")
for id := range uniqueIDs {
fmt.Printf(" - %s\n", id)
}
fmt.Printf("\n ⏳ Oldest entry is '%s' (modified on %s).\n",
filepath.Base(oldestEntry.Path), oldestEntry.ModTime.Format(time.RFC1123))
targetID := oldestEntry.ParentID
fmt.Printf(" ✅ Proposed target Parent ID: %s\n", targetID)
fmt.Printf("\n Do you want to unify all parent IDs to '%s'? This will modify %d entries, the directory, and the user index. (y/N): ", targetID, len(entries))
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(strings.ToLower(input))
if input != "y" {
spinner.Unpause()
logFailure("Operation cancelled by user.")
return
}
restartRequired = true
obsoleteIDs := []string{}
for id := range uniqueIDs {
if id != targetID {
obsoleteIDs = append(obsoleteIDs, id)
}
}
fixSpaceID(spacePath, obsoleteIDs, targetID, entries)
spinner.Unpause()
}
}
func walkNodes(dir string, parentID string) int {
fixes := 0
entries, err := os.ReadDir(dir)
if err != nil {
logFailure("Error reading directory '%s': %v", dir, err)
return 0
}
for _, entry := range entries {
fullPath := filepath.Join(dir, entry.Name())
if ignorer.IsIgnored(fullPath) {
continue
}
// Check if the parent ID attribute matches the expected parent ID, if not, fix it.
actualParentID, err := xattr.Get(fullPath, parentIDAttrName)
if err != nil || string(actualParentID) != parentID {
err = xattr.Set(fullPath, parentIDAttrName, []byte(parentID))
if err != nil {
logFailure("Failed to fix parent ID for '%s': %v", fullPath, err)
} else {
spinner.Pause()
fmt.Printf(" + Fixed parent ID for '%s'", fullPath)
spinner.Unpause()
fixes++
restartRequired = true
}
}
// Check that the name attribute matches the actual name of the file/directory, if not, fix it.
nameAttr, err := xattr.Get(fullPath, nameAttrName)
if err != nil || string(nameAttr) != entry.Name() {
err = xattr.Set(fullPath, nameAttrName, []byte(entry.Name()))
if err != nil {
logFailure("Failed to fix name attribute for '%s': %v", fullPath, err)
} else {
spinner.Pause()
fmt.Printf(" + Fixed name attribute for '%s'", fullPath)
spinner.Unpause()
fixes++
restartRequired = true
}
}
if entry.IsDir() {
nodeID, err := xattr.Get(fullPath, idAttrName)
if err != nil || len(nodeID) == 0 {
logFailure("Directory '%s' missing '%s', skipping its children", fullPath, idAttrName)
continue
}
walkNodes(fullPath, string(nodeID))
}
}
return fixes
}
func checkNodeIDs(spacePath string) {
spinner.Message(" - checking nodes")
rootID, err := xattr.Get(spacePath, idAttrName)
if err != nil || len(rootID) == 0 {
logFailure("Space root '%s' missing '%s' attribute", spacePath, idAttrName)
return
}
fixes := walkNodes(spacePath, string(rootID))
if fixes > 0 {
spinner.Pause()
fmt.Printf("\n ✓ Fixed %d incorrect node attributes in %s\n", fixes, filepath.Base(spacePath))
spinner.Unpause()
}
}
func fixSpaceID(spacePath string, obsoleteIDs []string, targetID string, entries []EntryInfo) {
// Set all parentid attributes to the proper space ID
err := setAllParentIDAttributes(entries, targetID)
if err != nil {
logFailure("an error occurred during file attribute update: %v", err)
return
}
// Update space ID itself
fmt.Printf(" Updating directory '%s' with attribute '%s' -> %s\n", filepath.Base(spacePath), idAttrName, targetID)
err = xattr.Set(spacePath, idAttrName, []byte(targetID))
if err != nil {
logFailure("Failed to set attribute on directory '%s': %v", spacePath, err)
return
}
err = xattr.Set(spacePath, spaceIDAttrName, []byte(targetID))
if err != nil {
logFailure("Failed to set attribute on directory '%s': %v", spacePath, err)
return
}
// update the index
err = updateOwnerIndexFile(spacePath, obsoleteIDs)
if err != nil {
logFailure("Could not update the owner index file: %v", err)
}
}
func gatherAttributes(path string) ([]EntryInfo, map[string]struct{}, EntryInfo, error) {
dirEntries, err := os.ReadDir(path)
if err != nil {
return nil, nil, EntryInfo{}, fmt.Errorf("failed to read directory: %w", err)
}
var allEntries []EntryInfo
uniqueIDs := make(map[string]struct{})
var oldestEntry EntryInfo
oldestTime := time.Now().Add(100 * 365 * 24 * time.Hour) // Set to a future date to find the oldest entry
for _, entry := range dirEntries {
fullPath := filepath.Join(path, entry.Name())
if ignorer.IsIgnored(fullPath) {
continue
}
info, err := os.Stat(fullPath)
if err != nil {
errors = append(errors, err)
logFailure("error: %s", err)
if keepGoing {
continue
} else {
return errors
}
fmt.Printf(" - Warning: could not stat %s: %v\n", entry.Name(), err)
continue
}
path = filepath.Clean(path)
if _, err := os.Stat(path); err != nil {
errors = append(errors, err)
logFailure("error accessing '%s': %w", path, err)
if keepGoing {
continue
} else {
return errors
}
}
contained, _ := filepathx.IsSameOrContainedBy(rootPath, path)
switch {
case path == rootPath:
if err := personalSpaceDir(filepath.Join(path, "users")); err != nil {
errors = append(errors, err)
if !keepGoing {
return errors
}
}
if err := projectSpaceDir(filepath.Join(path, "projects")); err != nil {
errors = append(errors, err)
if !keepGoing {
return errors
}
}
case isSpaceRoot(path):
if err := spaceRoot(path); err != nil {
errors = append(errors, err)
if !keepGoing {
return errors
}
}
case contained:
if err := entity(path); err != nil {
errors = append(errors, err)
if !keepGoing {
return errors
}
}
default:
err := fmt.Errorf("error: the provided path '%s' is neither a space root nor contained by the storage root '%s'", path, rootPath)
errors = append(errors, err)
logFailure(err.Error())
if !keepGoing {
return errors
}
parentID, err := xattr.Get(fullPath, parentIDAttrName)
if err != nil {
continue // Skip if attribute doesn't exist or can't be read
}
entryInfo := EntryInfo{
Path: fullPath,
ModTime: info.ModTime(),
ParentID: string(parentID),
}
allEntries = append(allEntries, entryInfo)
uniqueIDs[string(parentID)] = struct{}{}
if entryInfo.ModTime.Before(oldestTime) {
oldestTime = entryInfo.ModTime
oldestEntry = entryInfo
}
}
return errors
return allEntries, uniqueIDs, oldestEntry, nil
}
func setAllParentIDAttributes(entries []EntryInfo, targetID string) error {
fmt.Printf(" Setting all parent IDs to '%s':\n", targetID)
for _, entry := range entries {
if entry.ParentID == targetID {
fmt.Printf(" - Skipping '%s' (already has target ID).\n", filepath.Base(entry.Path))
continue
}
fmt.Printf(" - Removing all attributes from '%s'. It will be re-assimilated\n", filepath.Base(entry.Path))
filepath.WalkDir(entry.Path, func(path string, d os.DirEntry, err error) error {
if err != nil {
return fmt.Errorf("error walking path '%s': %w", path, err)
}
// Remove all attributes from the file.
if err := removeAttributes(path); err != nil {
fmt.Printf("failed to remove attributes from '%s': %v", path, err)
}
return nil
})
}
return nil
}
// updateOwnerIndexFile handles the logic of reading, modifying, and writing the MessagePack index file.
func updateOwnerIndexFile(basePath string, obsoleteIDs []string) error {
fmt.Printf(" Rewriting index file '%s'\n", basePath)
ownerID, err := xattr.Get(basePath, ownerIDAttrName)
if err != nil {
return fmt.Errorf("could not get owner ID from oldest entry '%s' to find index: %w", basePath, err)
}
indexPath := filepath.Join(basePath, "../../indexes/by-user-id", string(ownerID)+".mpk")
indexPath = filepath.Clean(indexPath)
// Read the MessagePack file
fileData, err := os.ReadFile(indexPath)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("index file does not exist, skipping update")
}
return fmt.Errorf("could not read index file: %w", err)
}
var indexMap map[string]string
if err := msgpack.Unmarshal(fileData, &indexMap); err != nil {
return fmt.Errorf("failed to parse MessagePack index file (is it corrupt?): %w", err)
}
// Remove obsolete IDs from the map
itemsRemoved := 0
for _, id := range obsoleteIDs {
if _, exists := indexMap[id]; exists {
fmt.Printf(" - Removing obsolete ID '%s' from index.\n", id)
delete(indexMap, id)
itemsRemoved++
} else {
fmt.Printf(" - Obsolete ID '%s' not found in index\n", id)
}
}
if itemsRemoved == 0 {
return nil
}
// Write the data back to the file
updatedData, err := msgpack.Marshal(&indexMap)
if err != nil {
return fmt.Errorf("failed to marshal updated index map: %w", err)
}
if err := os.WriteFile(indexPath, updatedData, 0644); err != nil {
return fmt.Errorf("failed to write updated index file: %w", err)
}
fmt.Printf(" ✓ Successfully removed %d item(s) and saved index file.\n", itemsRemoved)
return nil
}
func removeAttributes(path string) error {
attrNames, err := xattr.List(path)
if err != nil {
return fmt.Errorf("failed to list attributes for '%s': %w", path, err)
}
for _, attrName := range attrNames {
if err := xattr.Remove(path, attrName); err != nil {
return fmt.Errorf("failed to remove attribute '%s' from '%s': %w", attrName, path, err)
}
}
return nil
}
func logFailure(message string, args ...any) {
spinner.StopFailMessage(fmt.Sprintf("\n"+message, args...))
spinner.StopFail()
spinner.Start()
}
@@ -1,489 +0,0 @@
// Copyright 2026 OpenCloud GmbH <mail@opencloud.eu>
// SPDX-License-Identifier: Apache-2.0
package command
import (
"bufio"
"bytes"
"context"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
storageUsersConfig "github.com/opencloud-eu/opencloud/services/storage-users/pkg/config"
"github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore"
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes"
"github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node"
"github.com/pkg/xattr"
"github.com/shamaton/msgpack/v2"
)
type consistencyChecker struct {
cfg *storageUsersConfig.Config
ignorer *ignore.Ignorer
recalculateChecksums bool
restartRequired bool
}
// checkPosixfsConsistency checks the consistency of the posixfs storage. The
// given path determines the scope of the check: the whole storage, a single
// space or a single entity within a space.
func (c *consistencyChecker) Check(paths []string) error {
_ = processPosixFsResources(paths, true,
func(path string) error {
fmt.Println("Checking personal spaces...")
c.checkSpaces(path)
return nil
},
func(path string) error {
fmt.Println("Checking project spaces...")
c.checkSpaces(path)
return nil
},
func(path string) error {
fmt.Printf("Checking space '%s'...\n", path)
c.checkSpace(path)
return nil
},
func(path string) error {
if c.ignorer.IsIgnored(path) {
return nil
}
fmt.Printf("Checking '%s'...\n", path)
c.checkEntity(path)
return nil
},
)
if c.restartRequired {
fmt.Println("\n\n ⚠️ Please restart your openCloud instance to apply changes.")
}
return nil
}
func (c *consistencyChecker) checkSpaces(basePath string) {
dirEntries, err := os.ReadDir(basePath)
if err != nil {
logFailure("Error reading spaces directory '%s': %v", basePath, err)
return
}
for _, entry := range dirEntries {
if entry.IsDir() {
fullPath := filepath.Join(basePath, entry.Name())
c.checkSpace(fullPath)
}
}
}
func (c *consistencyChecker) checkSpace(spacePath string) {
info, err := os.Stat(spacePath)
if err != nil {
logFailure("Error accessing path '%s': %v", spacePath, err)
return
}
if !info.IsDir() {
logFailure("Error: The provided path '%s' is not a directory\n", spacePath)
return
}
spaceID, err := xattr.Get(spacePath, prefixes.SpaceIDAttr)
if err != nil || len(spaceID) == 0 {
logFailure("Error: The directory '%s' does not seem to be a space root, it's missing the '%s' attribute\n", spacePath, prefixes.SpaceIDAttr)
return
}
c.checkSpaceID(spacePath)
c.checkNodes(spacePath)
}
func (c *consistencyChecker) checkSpaceID(spacePath string) {
entries, uniqueIDs, oldestEntry, err := c.gatherAttributes(spacePath)
if err != nil {
logFailure("Failed to gather attributes: %v", err)
return
}
if len(entries) == 0 {
return
}
if len(uniqueIDs) > 1 {
fmt.Println("\n ⚠ Multiple space IDs found:")
for id := range uniqueIDs {
fmt.Printf(" - %s\n", id)
}
fmt.Printf("\n ⏳ Oldest entry is '%s' (modified on %s).\n",
filepath.Base(oldestEntry.Path), oldestEntry.ModTime.Format(time.RFC1123))
targetID := oldestEntry.ParentID
fmt.Printf(" ✅ Proposed target Parent ID: %s\n", targetID)
fmt.Printf("\n Do you want to unify all parent IDs to '%s'? This will modify %d entries, the directory, and the user index. (y/N): ", targetID, len(entries))
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(strings.ToLower(input))
if input != "y" {
logFailure("Operation cancelled by user.")
return
}
c.restartRequired = true
obsoleteIDs := []string{}
for id := range uniqueIDs {
if id != targetID {
obsoleteIDs = append(obsoleteIDs, id)
}
}
c.fixSpaceID(spacePath, obsoleteIDs, targetID, entries)
}
}
func (c *consistencyChecker) walkNodes(dir string, parentID string) int {
fixes := 0
entries, err := os.ReadDir(dir)
if err != nil {
logFailure("Error reading directory '%s': %v", dir, err)
return 0
}
for _, entry := range entries {
fullPath := filepath.Join(dir, entry.Name())
if c.ignorer.IsIgnored(fullPath) {
continue
}
fixes += c.checkNodeAttributes(fullPath, entry.Name(), parentID, entry.IsDir())
if entry.IsDir() {
nodeID, err := xattr.Get(fullPath, prefixes.IDAttr)
if err != nil || len(nodeID) == 0 {
logFailure("Directory '%s' missing '%s', skipping its children", fullPath, prefixes.IDAttr)
continue
}
fixes += c.walkNodes(fullPath, string(nodeID))
}
}
return fixes
}
// checkNodeAttributes checks and fixes the parent ID and name attributes of a
// single node. For files it additionally checks the blobsize and, when
// requested, the checksums. It returns the number of fixes applied.
func (c *consistencyChecker) checkNodeAttributes(path, name, parentID string, isDir bool) int {
fixes := 0
// Check if the parent ID attribute matches the expected parent ID, if not, fix it.
actualParentID, err := xattr.Get(path, prefixes.ParentidAttr)
if err != nil || string(actualParentID) != parentID {
if err := xattr.Set(path, prefixes.ParentidAttr, []byte(parentID)); err != nil {
logFailure("Failed to fix parent ID for '%s': %v", path, err)
} else {
fmt.Printf(" + Fixed parent ID for '%s'\n", path)
fixes++
c.restartRequired = true
}
}
// Check that the name attribute matches the actual name of the file/directory, if not, fix it.
nameAttr, err := xattr.Get(path, prefixes.NameAttr)
if err != nil || string(nameAttr) != name {
if err := xattr.Set(path, prefixes.NameAttr, []byte(name)); err != nil {
logFailure("Failed to fix name attribute for '%s': %v", path, err)
} else {
fmt.Printf(" + Fixed name attribute for '%s'\n", path)
fixes++
c.restartRequired = true
}
}
if !isDir {
fixes += c.checkBlobsize(path)
if c.recalculateChecksums {
fixes += c.fixChecksums(path)
}
}
return fixes
}
// checkEntity checks a single file or directory within a space, including its own
// parent ID, name and (for files) blobsize/checksums. If the entity is a directory
// its children are checked recursively.
func (c *consistencyChecker) checkEntity(path string) {
info, err := os.Stat(path)
if err != nil {
logFailure("Error accessing path '%s': %v", path, err)
return
}
// The expected parent ID is the ID attribute of the containing directory.
parentDir := filepath.Dir(path)
parentID, err := xattr.Get(parentDir, prefixes.IDAttr)
if err != nil || len(parentID) == 0 {
logFailure("Parent directory '%s' is missing the '%s' attribute", parentDir, prefixes.IDAttr)
return
}
fixes := c.checkNodeAttributes(path, info.Name(), string(parentID), info.IsDir())
if info.IsDir() {
nodeID, err := xattr.Get(path, prefixes.IDAttr)
if err != nil || len(nodeID) == 0 {
logFailure("Directory '%s' missing '%s' attribute", path, prefixes.IDAttr)
} else {
fixes += c.walkNodes(path, string(nodeID))
}
}
if fixes > 0 {
fmt.Printf(" ✓ Fixed %d incorrect node attributes for %s\n", fixes, filepath.Base(path))
}
}
// checkBlobsize verifies that the stored blobsize attribute matches the actual
// file size and fixes it if it doesn't. It returns the number of fixes applied.
func (c *consistencyChecker) checkBlobsize(path string) int {
info, err := os.Stat(path)
if err != nil {
logFailure("Error accessing file '%s': %v", path, err)
return 0
}
expectedSize := strconv.FormatInt(info.Size(), 10)
blobsize, err := xattr.Get(path, prefixes.BlobsizeAttr)
if err == nil && string(blobsize) == expectedSize {
return 0
}
if err := xattr.Set(path, prefixes.BlobsizeAttr, []byte(expectedSize)); err != nil {
logFailure("Failed to fix blobsize for '%s': %v", path, err)
return 0
}
fmt.Printf(" + Fixed blobsize for '%s'\n", path)
c.restartRequired = true
return 1
}
// fixChecksums recalculates the sha1, md5 and adler32 checksums of the file and
// updates the stored attributes if they differ. It returns the number of fixes applied.
func (c *consistencyChecker) fixChecksums(path string) int {
sha1h, md5h, adler32h, err := node.CalculateChecksums(context.Background(), path)
if err != nil {
logFailure("Failed to calculate checksums for '%s': %v", path, err)
return 0
}
checksums := map[string][]byte{
prefixes.ChecksumPrefix + "sha1": sha1h.Sum(nil),
prefixes.ChecksumPrefix + "md5": md5h.Sum(nil),
prefixes.ChecksumPrefix + "adler32": adler32h.Sum(nil),
}
fixes := 0
for attrName, sum := range checksums {
current, err := xattr.Get(path, attrName)
if err == nil && bytes.Equal(current, sum) {
continue
}
if err := xattr.Set(path, attrName, sum); err != nil {
logFailure("Failed to fix checksum '%s' for '%s': %v", attrName, path, err)
continue
}
fmt.Printf(" + Fixed checksum '%s' for '%s'\n", attrName, path)
c.restartRequired = true
fixes++
}
return fixes
}
func (c *consistencyChecker) checkNodes(spacePath string) {
rootID, err := xattr.Get(spacePath, prefixes.IDAttr)
if err != nil || len(rootID) == 0 {
logFailure("Space root '%s' missing '%s' attribute", spacePath, prefixes.IDAttr)
return
}
fixes := c.walkNodes(spacePath, string(rootID))
if fixes > 0 {
fmt.Printf(" ✓ Fixed %d incorrect node attributes in %s\n", fixes, filepath.Base(spacePath))
}
}
// fixSpaceID updates the parentid attributes of all entries in a space to a new target ID,
// updates the space's own ID attributes, and removes obsolete IDs from the user index file.
func (c *consistencyChecker) fixSpaceID(spacePath string, obsoleteIDs []string, targetID string, entries []EntryInfo) {
// Set all parentid attributes to the proper space ID
err := setAllParentIDAttributes(entries, targetID)
if err != nil {
logFailure("an error occurred during file attribute update: %v", err)
return
}
// Update space ID itself
fmt.Printf(" Updating directory '%s' with attribute '%s' -> %s\n", filepath.Base(spacePath), prefixes.IDAttr, targetID)
err = xattr.Set(spacePath, prefixes.IDAttr, []byte(targetID))
if err != nil {
logFailure("Failed to set attribute on directory '%s': %v", spacePath, err)
return
}
err = xattr.Set(spacePath, prefixes.SpaceIDAttr, []byte(targetID))
if err != nil {
logFailure("Failed to set attribute on directory '%s': %v", spacePath, err)
return
}
// update the index
err = c.updateOwnerIndexFile(spacePath, obsoleteIDs)
if err != nil {
logFailure("Could not update the owner index file: %v", err)
}
}
func (c *consistencyChecker) gatherAttributes(path string) ([]EntryInfo, map[string]struct{}, EntryInfo, error) {
dirEntries, err := os.ReadDir(path)
if err != nil {
return nil, nil, EntryInfo{}, fmt.Errorf("failed to read directory: %w", err)
}
var allEntries []EntryInfo
uniqueIDs := make(map[string]struct{})
var oldestEntry EntryInfo
oldestTime := time.Now().Add(100 * 365 * 24 * time.Hour) // Set to a future date to find the oldest entry
for _, entry := range dirEntries {
fullPath := filepath.Join(path, entry.Name())
if c.ignorer.IsIgnored(fullPath) {
continue
}
info, err := os.Stat(fullPath)
if err != nil {
fmt.Printf(" - Warning: could not stat %s: %v\n", entry.Name(), err)
continue
}
parentID, err := xattr.Get(fullPath, prefixes.ParentidAttr)
if err != nil {
continue // Skip if attribute doesn't exist or can't be read
}
entryInfo := EntryInfo{
Path: fullPath,
ModTime: info.ModTime(),
ParentID: string(parentID),
}
allEntries = append(allEntries, entryInfo)
uniqueIDs[string(parentID)] = struct{}{}
if entryInfo.ModTime.Before(oldestTime) {
oldestTime = entryInfo.ModTime
oldestEntry = entryInfo
}
}
return allEntries, uniqueIDs, oldestEntry, nil
}
func setAllParentIDAttributes(entries []EntryInfo, targetID string) error {
fmt.Printf(" Setting all parent IDs to '%s':\n", targetID)
for _, entry := range entries {
if entry.ParentID == targetID {
fmt.Printf(" - Skipping '%s' (already has target ID).\n", filepath.Base(entry.Path))
continue
}
fmt.Printf(" - Removing all attributes from '%s'. It will be re-assimilated\n", filepath.Base(entry.Path))
filepath.WalkDir(entry.Path, func(path string, d os.DirEntry, err error) error {
if err != nil {
return fmt.Errorf("error walking path '%s': %w", path, err)
}
// Remove all attributes from the file.
if err := removeAttributes(path); err != nil {
fmt.Printf("failed to remove attributes from '%s': %v", path, err)
}
return nil
})
}
return nil
}
// updateOwnerIndexFile handles the logic of reading, modifying, and writing the MessagePack index file.
func (c *consistencyChecker) updateOwnerIndexFile(basePath string, obsoleteIDs []string) error {
fmt.Printf(" Rewriting index file '%s'\n", basePath)
ownerID, err := xattr.Get(basePath, prefixes.OwnerIDAttr)
if err != nil {
return fmt.Errorf("could not get owner ID from oldest entry '%s' to find index: %w", basePath, err)
}
indexPath := filepath.Join(c.cfg.Drivers.Posix.Root, "indexes", "by-user-id", string(ownerID)+".mpk")
indexPath = filepath.Clean(indexPath)
// Read the MessagePack file
fileData, err := os.ReadFile(indexPath)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("index file does not exist, skipping update")
}
return fmt.Errorf("could not read index file: %w", err)
}
var indexMap map[string]string
if err := msgpack.Unmarshal(fileData, &indexMap); err != nil {
return fmt.Errorf("failed to parse MessagePack index file (is it corrupt?): %w", err)
}
// Remove obsolete IDs from the map
itemsRemoved := 0
for _, id := range obsoleteIDs {
if _, exists := indexMap[id]; exists {
fmt.Printf(" - Removing obsolete ID '%s' from index.\n", id)
delete(indexMap, id)
itemsRemoved++
} else {
fmt.Printf(" - Obsolete ID '%s' not found in index\n", id)
}
}
if itemsRemoved == 0 {
return nil
}
// Write the data back to the file
updatedData, err := msgpack.Marshal(&indexMap)
if err != nil {
return fmt.Errorf("failed to marshal updated index map: %w", err)
}
if err := os.WriteFile(indexPath, updatedData, 0644); err != nil {
return fmt.Errorf("failed to write updated index file: %w", err)
}
fmt.Printf(" ✓ Successfully removed %d item(s) and saved index file.\n", itemsRemoved)
return nil
}
func removeAttributes(path string) error {
attrNames, err := xattr.List(path)
if err != nil {
return fmt.Errorf("failed to list attributes for '%s': %w", path, err)
}
for _, attrName := range attrNames {
if err := xattr.Remove(path, attrName); err != nil {
return fmt.Errorf("failed to remove attribute '%s' from '%s': %w", attrName, path, err)
}
}
return nil
}
+2 -12
View File
@@ -6,13 +6,11 @@ import (
"os/signal"
"syscall"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
"github.com/opencloud-eu/opencloud/opencloud/pkg/register"
"github.com/opencloud-eu/opencloud/pkg/clihelper"
"github.com/opencloud-eu/opencloud/pkg/config"
oclog "github.com/opencloud-eu/opencloud/pkg/log"
"github.com/spf13/cobra"
)
// Execute is the entry point for the opencloud command.
@@ -40,11 +38,3 @@ func Execute() error {
ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)
return app.ExecuteContext(ctx)
}
func logger(name string) zerolog.Logger {
return oclog.NewLogger(
oclog.Name(name),
oclog.Level("info"),
oclog.Pretty(true),
oclog.Color(true)).Logger
}
+12 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/opencloud-eu/opencloud/pkg/config"
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
"github.com/opencloud-eu/opencloud/pkg/config/parser"
oclog "github.com/opencloud-eu/opencloud/pkg/log"
mregistry "github.com/opencloud-eu/opencloud/pkg/registry"
sharing "github.com/opencloud-eu/opencloud/services/sharing/pkg/config"
sharingparser "github.com/opencloud-eu/opencloud/services/sharing/pkg/config/parser"
@@ -84,7 +85,7 @@ func cleanup(_ *cobra.Command, cfg *config.Config) error {
return configlog.ReturnError(errors.New("cleanup is only implemented for the jsoncs3 share manager"))
}
l := logger("migrate")
l := logger()
zerolog.SetGlobalLevel(zerolog.InfoLevel)
@@ -93,7 +94,7 @@ func cleanup(_ *cobra.Command, cfg *config.Config) error {
if !ok {
return configlog.ReturnError(errors.New("Unknown share manager type '" + driver + "'"))
}
mgr, err := f(rcfg[driver].(map[string]any), &l)
mgr, err := f(rcfg[driver].(map[string]any), l)
if err != nil {
return configlog.ReturnError(err)
}
@@ -166,3 +167,12 @@ func revaShareConfig(cfg *sharing.Config) map[string]any {
},
}
}
func logger() *zerolog.Logger {
log := oclog.NewLogger(
oclog.Name("migrate"),
oclog.Level("info"),
oclog.Pretty(true),
oclog.Color(true)).Logger
return &log
}
+3 -10
View File
@@ -389,16 +389,9 @@ func Start(ctx context.Context, o ...Option) error {
if ev.Restarting {
l = s.Log.Error()
}
l = l.Str("event", e.String()).Str("service", ev.ServiceName).Str("supervisor", ev.SupervisorName).
Bool("restarting", ev.Restarting).Float64("failures", ev.CurrentFailures).Float64("threshold", ev.FailureThreshold)
// ev.Err is an interface{}: marshaling an error yields {} because
// its fields are unexported, so the message has to go through Err
if err, ok := ev.Err.(error); ok {
l = l.Err(err)
} else {
l = l.Interface("error", ev.Err)
}
l.Msg("service terminated")
l.Str("event", e.String()).Str("service", ev.ServiceName).Str("supervisor", ev.SupervisorName).
Bool("restarting", ev.Restarting).Float64("failures", ev.CurrentFailures).Float64("threshold", ev.FailureThreshold).
Interface("error", ev.Err).Msg("service terminated")
case suture.EventBackoff:
s.Log.Warn().Str("event", e.String()).Str("supervisor", ev.SupervisorName).Msg("service backoff")
case suture.EventResume:
-12
View File
@@ -14,17 +14,5 @@ func DefaultApp(app *cobra.Command) *cobra.Command {
// version info
app.Version = fmt.Sprintf("%s (%s <%s>) (%s)", version.String, "OpenCloud GmbH", "support@opencloud.eu", version.Compiled())
// cobra would print the error on top of what main() already prints
app.SilenceErrors = true
// keep the usage block for flag parse errors, drop it once RunE runs.
// Traversing runs the hook even below a subcommand that brings its own,
// e.g. every service below ServiceCommand.
cobra.EnableTraverseRunHooks = true
app.PersistentPreRunE = func(cmd *cobra.Command, _ []string) error {
cmd.SilenceUsage = true
return nil
}
return app
}
-8
View File
@@ -101,11 +101,3 @@ func MissingURLSigningSecret(service string) error {
"the config/corresponding environment variable).",
service, defaults.BaseConfigPath())
}
func AllComponentsDisabledError(service string) error {
return fmt.Errorf("All request handlers and event consumers are disabled for %s; at least one component must be enabled."+
"Make sure your %s config contains the proper values "+
"(e.g. by using 'opencloud init --diff' and applying the patch or setting a value manually in "+
"the config/corresponding environment variable).",
service, defaults.BaseConfigPath())
}
+1 -1
View File
@@ -34,7 +34,7 @@ var (
// LatestTag is the latest released version plus the dev meta version.
// Will be overwritten by the release pipeline
// Needs a manual change for every tagged release
LatestTag = "7.5.0+dev"
LatestTag = "7.3.0+dev"
// Date indicates the build date.
// This has been removed, it looks like you can only replace static strings with recent go versions
-26
View File
@@ -1,9 +1,7 @@
package filepathx
import (
"fmt"
"path/filepath"
"strings"
)
// JailJoin joins any number of path elements into a single path,
@@ -12,27 +10,3 @@ import (
func JailJoin(jail string, elem ...string) string {
return filepath.Join(jail, filepath.Join(append([]string{"/"}, elem...)...))
}
// Determines whether the file or directory 'child' is same as or underneath the directory 'parent'.
//
// Note that 'parent' is expected to be a directory.
func IsSameOrContainedBy(parent string, child string) (bool, error) {
absParent, err := filepath.Abs(parent)
if err != nil {
return false, fmt.Errorf("failed to make parent directory absolute: %q: %w", parent, err)
}
absChild, err := filepath.Abs(child)
if err != nil {
return false, fmt.Errorf("failed to make child file/directory absolute: %q: %w", child, err)
}
rel, err := filepath.Rel(absParent, absChild)
if err != nil {
return false, fmt.Errorf("failed to determine the relative path between the parent directory %q and the child file/directory: %q: %w", absParent, absChild, err)
}
if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
return false, nil
}
return true, nil
}
-23
View File
@@ -1,12 +1,9 @@
package filepathx_test
import (
"fmt"
"strings"
"testing"
"github.com/opencloud-eu/opencloud/pkg/x/path/filepathx"
"github.com/stretchr/testify/require"
)
func TestJailJoin(t *testing.T) {
@@ -64,23 +61,3 @@ func TestJailJoin(t *testing.T) {
})
}
}
func TestIsSameOrContainedBy(t *testing.T) {
for _, tt := range []struct {
parent string
child string
expected bool
}{
{"foo", "foo", true},
{"/foo", "/foo", true},
{"foo", "foo/bar", true},
{"foo", "bar", false},
} {
t.Run(fmt.Sprintf("%s: %s vs %s", t.Name(), strings.ReplaceAll(tt.parent, "/", "."), strings.ReplaceAll(tt.child, "/", ".")), func(t *testing.T) {
require := require.New(t)
b, err := filepathx.IsSameOrContainedBy(tt.parent, tt.child)
require.NoError(err)
require.Equal(tt.expected, b)
})
}
}
@@ -627,13 +627,13 @@ type Bundle struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty" yaml:"type"` // @gotags: yaml:"type"
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty" yaml:"extension"` // @gotags: yaml:"extension"
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty" yaml:"settings"` // @gotags: yaml:"settings"
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty"` // @gotags: yaml:"type"
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"` // @gotags: yaml:"extension"
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty"` // @gotags: yaml:"settings"
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
}
func (x *Bundle) Reset() {
@@ -722,10 +722,10 @@ type Setting struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` // @gotags: yaml:"description"
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // @gotags: yaml:"description"
// Types that are assignable to Value:
//
// *Setting_IntValue
@@ -736,7 +736,7 @@ type Setting struct {
// *Setting_PermissionValue
// *Setting_MultiChoiceCollectionValue
Value isSetting_Value `protobuf_oneof:"value"`
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
}
func (x *Setting) Reset() {
@@ -867,31 +867,31 @@ type isSetting_Value interface {
}
type Setting_IntValue struct {
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type Setting_StringValue struct {
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type Setting_BoolValue struct {
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
type Setting_SingleChoiceValue struct {
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof" yaml:"single_choice_value"` // @gotags: yaml:"single_choice_value"
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof"` // @gotags: yaml:"single_choice_value"
}
type Setting_MultiChoiceValue struct {
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof" yaml:"multi_choice_value"` // @gotags: yaml:"multi_choice_value"
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof"` // @gotags: yaml:"multi_choice_value"
}
type Setting_PermissionValue struct {
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof" yaml:"permission_value"` // @gotags: yaml:"permission_value"
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof"` // @gotags: yaml:"permission_value"
}
type Setting_MultiChoiceCollectionValue struct {
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof" yaml:"multi_choice_collection_value"` // @gotags: yaml:"multi_choice_collection_value"
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof"` // @gotags: yaml:"multi_choice_collection_value"
}
func (*Setting_IntValue) isSetting_Value() {}
@@ -913,11 +913,11 @@ type Int struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty" yaml:"min"` // @gotags: yaml:"min"
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty" yaml:"max"` // @gotags: yaml:"max"
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty" yaml:"step"` // @gotags: yaml:"step"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty"` // @gotags: yaml:"min"
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` // @gotags: yaml:"max"
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty"` // @gotags: yaml:"step"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
}
func (x *Int) Reset() {
@@ -992,11 +992,11 @@ type String struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty" yaml:"required"` // @gotags: yaml:"required"
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty" yaml:"min_length"` // @gotags: yaml:"min_length"
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty" yaml:"max_length"` // @gotags: yaml:"max_length"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty"` // @gotags: yaml:"required"
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` // @gotags: yaml:"min_length"
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` // @gotags: yaml:"max_length"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
}
func (x *String) Reset() {
@@ -1071,8 +1071,8 @@ type Bool struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty" yaml:"label"` // @gotags: yaml:"label"
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // @gotags: yaml:"label"
}
func (x *Bool) Reset() {
@@ -1126,7 +1126,7 @@ type SingleChoiceList struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
}
func (x *SingleChoiceList) Reset() {
@@ -1173,7 +1173,7 @@ type MultiChoiceList struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
}
func (x *MultiChoiceList) Reset() {
@@ -1220,9 +1220,9 @@ type ListOption struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
}
func (x *ListOption) Reset() {
@@ -1283,7 +1283,7 @@ type MultiChoiceCollection struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
}
func (x *MultiChoiceCollection) Reset() {
@@ -1330,10 +1330,10 @@ type MultiChoiceCollectionOption struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty" yaml:"attribute"` // @gotags: yaml:"attribute"
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty"` // @gotags: yaml:"attribute"
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
}
func (x *MultiChoiceCollectionOption) Reset() {
@@ -1474,15 +1474,15 @@ type isMultiChoiceCollectionOptionValue_Option interface {
}
type MultiChoiceCollectionOptionValue_IntValue struct {
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type MultiChoiceCollectionOptionValue_StringValue struct {
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type MultiChoiceCollectionOptionValue_BoolValue struct {
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
func (*MultiChoiceCollectionOptionValue_IntValue) isMultiChoiceCollectionOptionValue_Option() {}
@@ -1496,8 +1496,8 @@ type Permission struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty" yaml:"operation"` // @gotags: yaml:"operation"
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty" yaml:"constraint"` // @gotags: yaml:"constraint"
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty"` // @gotags: yaml:"operation"
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty"` // @gotags: yaml:"constraint"
}
func (x *Permission) Reset() {
@@ -1552,12 +1552,12 @@ type Value struct {
unknownFields protoimpl.UnknownFields
// id is the id of the Value. It is generated on saving it.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty" yaml:"bundle_id"` // @gotags: yaml:"bundle_id"
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty"` // @gotags: yaml:"bundle_id"
// setting_id is the id of the setting from within its bundle.
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty" yaml:"setting_id"` // @gotags: yaml:"setting_id"
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty" yaml:"account_uuid"` // @gotags: yaml:"account_uuid"
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty"` // @gotags: yaml:"setting_id"
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty"` // @gotags: yaml:"account_uuid"
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
// Types that are assignable to Value:
//
// *Value_BoolValue
@@ -1682,23 +1682,23 @@ type isValue_Value interface {
}
type Value_BoolValue struct {
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
type Value_IntValue struct {
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type Value_StringValue struct {
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type Value_ListValue struct {
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof" yaml:"list_value"` // @gotags: yaml:"list_value"
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof"` // @gotags: yaml:"list_value"
}
type Value_CollectionValue struct {
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof" yaml:"collection_value"` // @gotags: yaml:"collection_value"
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof"` // @gotags: yaml:"collection_value"
}
func (*Value_BoolValue) isValue_Value() {}
@@ -1716,7 +1716,7 @@ type ListValue struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
}
func (x *ListValue) Reset() {
@@ -1836,15 +1836,15 @@ type isListOptionValue_Option interface {
}
type ListOptionValue_StringValue struct {
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type ListOptionValue_IntValue struct {
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type ListOptionValue_BoolValue struct {
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
func (*ListOptionValue_StringValue) isListOptionValue_Option() {}
@@ -1858,7 +1858,7 @@ type CollectionValue struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
}
func (x *CollectionValue) Reset() {
@@ -1906,7 +1906,7 @@ type CollectionOption struct {
unknownFields protoimpl.UnknownFields
// required
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
// Types that are assignable to Option:
//
// *CollectionOption_IntValue
@@ -1987,15 +1987,15 @@ type isCollectionOption_Option interface {
}
type CollectionOption_IntValue struct {
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type CollectionOption_StringValue struct {
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type CollectionOption_BoolValue struct {
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
func (*CollectionOption_IntValue) isCollectionOption_Option() {}
@@ -40,7 +40,7 @@ func (_m *SearchProviderService) EXPECT() *SearchProviderService_Expecter {
}
// IndexSpace provides a mock function for the type SearchProviderService
func (_mock *SearchProviderService) IndexSpace(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (v0.SearchProvider_IndexSpaceService, error) {
func (_mock *SearchProviderService) IndexSpace(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (*v0.IndexSpaceResponse, error) {
var tmpRet mock.Arguments
if len(opts) > 0 {
tmpRet = _mock.Called(ctx, in, opts)
@@ -53,16 +53,16 @@ func (_mock *SearchProviderService) IndexSpace(ctx context.Context, in *v0.Index
panic("no return value specified for IndexSpace")
}
var r0 v0.SearchProvider_IndexSpaceService
var r0 *v0.IndexSpaceResponse
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) (v0.SearchProvider_IndexSpaceService, error)); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) (*v0.IndexSpaceResponse, error)); ok {
return returnFunc(ctx, in, opts...)
}
if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) v0.SearchProvider_IndexSpaceService); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) *v0.IndexSpaceResponse); ok {
r0 = returnFunc(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(v0.SearchProvider_IndexSpaceService)
r0 = ret.Get(0).(*v0.IndexSpaceResponse)
}
}
if returnFunc, ok := ret.Get(1).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) error); ok {
@@ -112,12 +112,12 @@ func (_c *SearchProviderService_IndexSpace_Call) Run(run func(ctx context.Contex
return _c
}
func (_c *SearchProviderService_IndexSpace_Call) Return(searchProvider_IndexSpaceService v0.SearchProvider_IndexSpaceService, err error) *SearchProviderService_IndexSpace_Call {
_c.Call.Return(searchProvider_IndexSpaceService, err)
func (_c *SearchProviderService_IndexSpace_Call) Return(indexSpaceResponse *v0.IndexSpaceResponse, err error) *SearchProviderService_IndexSpace_Call {
_c.Call.Return(indexSpaceResponse, err)
return _c
}
func (_c *SearchProviderService_IndexSpace_Call) RunAndReturn(run func(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (v0.SearchProvider_IndexSpaceService, error)) *SearchProviderService_IndexSpace_Call {
func (_c *SearchProviderService_IndexSpace_Call) RunAndReturn(run func(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (*v0.IndexSpaceResponse, error)) *SearchProviderService_IndexSpace_Call {
_c.Call.Return(run)
return _c
}
@@ -12,7 +12,6 @@ import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
durationpb "google.golang.org/protobuf/types/known/durationpb"
_ "google.golang.org/protobuf/types/known/fieldmaskpb"
reflect "reflect"
sync "sync"
@@ -311,7 +310,6 @@ type IndexSpaceRequest struct {
SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"`
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
ForceReindex bool `protobuf:"varint,3,opt,name=force_reindex,json=forceReindex,proto3" json:"force_reindex,omitempty"`
Concurrency int32 `protobuf:"varint,4,opt,name=concurrency,proto3" json:"concurrency,omitempty"`
}
func (x *IndexSpaceRequest) Reset() {
@@ -367,28 +365,10 @@ func (x *IndexSpaceRequest) GetForceReindex() bool {
return false
}
func (x *IndexSpaceRequest) GetConcurrency() int32 {
if x != nil {
return x.Concurrency
}
return 0
}
type IndexSpaceResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The id of the space that has just been indexed.
SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"`
// The duration it took to index this space.
SpaceDuration *durationpb.Duration `protobuf:"bytes,2,opt,name=space_duration,json=spaceDuration,proto3" json:"space_duration,omitempty"`
// The number of spaces that have been indexed so far.
IndexedSpaces int64 `protobuf:"varint,3,opt,name=indexed_spaces,json=indexedSpaces,proto3" json:"indexed_spaces,omitempty"`
// The total number of spaces that are being indexed.
TotalSpaces int64 `protobuf:"varint,4,opt,name=total_spaces,json=totalSpaces,proto3" json:"total_spaces,omitempty"`
// Contains an error message in case indexing this particular space failed.
Error string `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"`
}
func (x *IndexSpaceResponse) Reset() {
@@ -423,41 +403,6 @@ func (*IndexSpaceResponse) Descriptor() ([]byte, []int) {
return file_opencloud_services_search_v0_search_proto_rawDescGZIP(), []int{5}
}
func (x *IndexSpaceResponse) GetSpaceId() string {
if x != nil {
return x.SpaceId
}
return ""
}
func (x *IndexSpaceResponse) GetSpaceDuration() *durationpb.Duration {
if x != nil {
return x.SpaceDuration
}
return nil
}
func (x *IndexSpaceResponse) GetIndexedSpaces() int64 {
if x != nil {
return x.IndexedSpaces
}
return 0
}
func (x *IndexSpaceResponse) GetTotalSpaces() int64 {
if x != nil {
return x.TotalSpaces
}
return 0
}
func (x *IndexSpaceResponse) GetError() string {
if x != nil {
return x.Error
}
return ""
}
var File_opencloud_services_search_v0_search_proto protoreflect.FileDescriptor
var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{
@@ -477,8 +422,6 @@ var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{
0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f,
0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x01,
@@ -522,83 +465,68 @@ var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{
0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f,
0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22,
0x94, 0x01, 0x0a, 0x11, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64,
0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x72,
0x63, 0x65, 0x5f, 0x72, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26,
0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20,
0x01, 0x28, 0x05, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x01, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0xd1, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78,
0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a,
0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x73, 0x70, 0x61, 0x63,
0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x70, 0x61,
0x63, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65,
0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65,
0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x70,
0x61, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x32, 0xb3, 0x02, 0x0a, 0x0e, 0x53,
0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x85, 0x01,
0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63,
0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65,
0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75,
0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63,
0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x73,
0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x98, 0x01, 0x0a, 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53,
0x70, 0x61, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75,
0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63,
0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a,
0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72,
0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x30, 0x01,
0x32, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x72, 0x12, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x30, 0x2e,
0x6c, 0x0a, 0x11, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12,
0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x72, 0x63,
0x65, 0x5f, 0x72, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x14, 0x0a,
0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x32, 0xb1, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x85, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63,
0x68, 0x12, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30,
0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c,
0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65,
0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30,
0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x96,
0x01, 0x0a, 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2f, 0x2e,
0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61,
0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x31, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53,
0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0xf2, 0x02, 0x5a, 0x4a, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c,
0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f, 0x70,
0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f,
0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x76, 0x30, 0x92, 0x41, 0xa2, 0x02, 0x12, 0xb7, 0x01,
0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x73, 0x65, 0x61, 0x72,
0x63, 0x68, 0x22, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20,
0x47, 0x6d, 0x62, 0x48, 0x12, 0x29, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f,
0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x1a,
0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f,
0x75, 0x64, 0x2e, 0x65, 0x75, 0x2a, 0x49, 0x0a, 0x0a, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2d,
0x32, 0x2e, 0x30, 0x12, 0x3b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75,
0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x62,
0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45,
0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61,
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72,
0x3e, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e,
0x75, 0x61, 0x6c, 0x12, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63,
0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x65, 0x75, 0x2f, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30,
0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65,
0x78, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x32, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65,
0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x65,
0x61, 0x72, 0x63, 0x68, 0x12, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f,
0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72,
0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65,
0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65,
0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63,
0x68, 0x42, 0xf2, 0x02, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70,
0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e,
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x76, 0x30,
0x92, 0x41, 0xa2, 0x02, 0x12, 0xb7, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6c, 0x6f,
0x75, 0x64, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x22, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65,
0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x12, 0x29, 0x68, 0x74, 0x74,
0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65,
0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x1a, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40,
0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x65, 0x75, 0x2a, 0x49, 0x0a, 0x0a,
0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x32, 0x2e, 0x30, 0x12, 0x3b, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e,
0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f,
0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02,
0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f,
0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f,
0x70, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x12, 0x2a, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f,
0x75, 0x64, 0x2e, 0x65, 0x75, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73,
0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -623,25 +551,23 @@ var file_opencloud_services_search_v0_search_proto_goTypes = []interface{}{
(*IndexSpaceResponse)(nil), // 5: opencloud.services.search.v0.IndexSpaceResponse
(*v0.Reference)(nil), // 6: opencloud.messages.search.v0.Reference
(*v0.Match)(nil), // 7: opencloud.messages.search.v0.Match
(*durationpb.Duration)(nil), // 8: google.protobuf.Duration
}
var file_opencloud_services_search_v0_search_proto_depIdxs = []int32{
6, // 0: opencloud.services.search.v0.SearchRequest.ref:type_name -> opencloud.messages.search.v0.Reference
7, // 1: opencloud.services.search.v0.SearchResponse.matches:type_name -> opencloud.messages.search.v0.Match
6, // 2: opencloud.services.search.v0.SearchIndexRequest.ref:type_name -> opencloud.messages.search.v0.Reference
7, // 3: opencloud.services.search.v0.SearchIndexResponse.matches:type_name -> opencloud.messages.search.v0.Match
8, // 4: opencloud.services.search.v0.IndexSpaceResponse.space_duration:type_name -> google.protobuf.Duration
0, // 5: opencloud.services.search.v0.SearchProvider.Search:input_type -> opencloud.services.search.v0.SearchRequest
4, // 6: opencloud.services.search.v0.SearchProvider.IndexSpace:input_type -> opencloud.services.search.v0.IndexSpaceRequest
2, // 7: opencloud.services.search.v0.IndexProvider.Search:input_type -> opencloud.services.search.v0.SearchIndexRequest
1, // 8: opencloud.services.search.v0.SearchProvider.Search:output_type -> opencloud.services.search.v0.SearchResponse
5, // 9: opencloud.services.search.v0.SearchProvider.IndexSpace:output_type -> opencloud.services.search.v0.IndexSpaceResponse
3, // 10: opencloud.services.search.v0.IndexProvider.Search:output_type -> opencloud.services.search.v0.SearchIndexResponse
8, // [8:11] is the sub-list for method output_type
5, // [5:8] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
0, // 4: opencloud.services.search.v0.SearchProvider.Search:input_type -> opencloud.services.search.v0.SearchRequest
4, // 5: opencloud.services.search.v0.SearchProvider.IndexSpace:input_type -> opencloud.services.search.v0.IndexSpaceRequest
2, // 6: opencloud.services.search.v0.IndexProvider.Search:input_type -> opencloud.services.search.v0.SearchIndexRequest
1, // 7: opencloud.services.search.v0.SearchProvider.Search:output_type -> opencloud.services.search.v0.SearchResponse
5, // 8: opencloud.services.search.v0.SearchProvider.IndexSpace:output_type -> opencloud.services.search.v0.IndexSpaceResponse
3, // 9: opencloud.services.search.v0.IndexProvider.Search:output_type -> opencloud.services.search.v0.SearchIndexResponse
7, // [7:10] is the sub-list for method output_type
4, // [4:7] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_opencloud_services_search_v0_search_proto_init() }
@@ -9,7 +9,6 @@ import (
_ "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/search/v0"
_ "google.golang.org/genproto/googleapis/api/annotations"
proto "google.golang.org/protobuf/proto"
_ "google.golang.org/protobuf/types/known/durationpb"
_ "google.golang.org/protobuf/types/known/fieldmaskpb"
math "math"
)
@@ -46,7 +45,6 @@ func NewSearchProviderEndpoints() []*api.Endpoint {
Name: "SearchProvider.IndexSpace",
Path: []string{"/api/v0/search/index-space"},
Method: []string{"POST"},
Stream: true,
Handler: "rpc",
},
}
@@ -56,9 +54,7 @@ func NewSearchProviderEndpoints() []*api.Endpoint {
type SearchProviderService interface {
Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error)
// IndexSpace (re)indexes one or all spaces. The response is streamed, sending
// progress information after each space has been indexed.
IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (SearchProvider_IndexSpaceService, error)
IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (*IndexSpaceResponse, error)
}
type searchProviderService struct {
@@ -83,73 +79,27 @@ func (c *searchProviderService) Search(ctx context.Context, in *SearchRequest, o
return out, nil
}
func (c *searchProviderService) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (SearchProvider_IndexSpaceService, error) {
req := c.c.NewRequest(c.name, "SearchProvider.IndexSpace", &IndexSpaceRequest{})
stream, err := c.c.Stream(ctx, req, opts...)
func (c *searchProviderService) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (*IndexSpaceResponse, error) {
req := c.c.NewRequest(c.name, "SearchProvider.IndexSpace", in)
out := new(IndexSpaceResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
if err := stream.Send(in); err != nil {
return nil, err
}
return &searchProviderServiceIndexSpace{stream}, nil
}
type SearchProvider_IndexSpaceService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Recv() (*IndexSpaceResponse, error)
}
type searchProviderServiceIndexSpace struct {
stream client.Stream
}
func (x *searchProviderServiceIndexSpace) CloseSend() error {
return x.stream.CloseSend()
}
func (x *searchProviderServiceIndexSpace) Close() error {
return x.stream.Close()
}
func (x *searchProviderServiceIndexSpace) Context() context.Context {
return x.stream.Context()
}
func (x *searchProviderServiceIndexSpace) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *searchProviderServiceIndexSpace) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *searchProviderServiceIndexSpace) Recv() (*IndexSpaceResponse, error) {
m := new(IndexSpaceResponse)
err := x.stream.Recv(m)
if err != nil {
return nil, err
}
return m, nil
return out, nil
}
// Server API for SearchProvider service
type SearchProviderHandler interface {
Search(context.Context, *SearchRequest, *SearchResponse) error
// IndexSpace (re)indexes one or all spaces. The response is streamed, sending
// progress information after each space has been indexed.
IndexSpace(context.Context, *IndexSpaceRequest, SearchProvider_IndexSpaceStream) error
IndexSpace(context.Context, *IndexSpaceRequest, *IndexSpaceResponse) error
}
func RegisterSearchProviderHandler(s server.Server, hdlr SearchProviderHandler, opts ...server.HandlerOption) error {
type searchProvider interface {
Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error
IndexSpace(ctx context.Context, stream server.Stream) error
IndexSpace(ctx context.Context, in *IndexSpaceRequest, out *IndexSpaceResponse) error
}
type SearchProvider struct {
searchProvider
@@ -165,7 +115,6 @@ func RegisterSearchProviderHandler(s server.Server, hdlr SearchProviderHandler,
Name: "SearchProvider.IndexSpace",
Path: []string{"/api/v0/search/index-space"},
Method: []string{"POST"},
Stream: true,
Handler: "rpc",
}))
return s.Handle(s.NewHandler(&SearchProvider{h}, opts...))
@@ -179,44 +128,8 @@ func (h *searchProviderHandler) Search(ctx context.Context, in *SearchRequest, o
return h.SearchProviderHandler.Search(ctx, in, out)
}
func (h *searchProviderHandler) IndexSpace(ctx context.Context, stream server.Stream) error {
m := new(IndexSpaceRequest)
if err := stream.Recv(m); err != nil {
return err
}
return h.SearchProviderHandler.IndexSpace(ctx, m, &searchProviderIndexSpaceStream{stream})
}
type SearchProvider_IndexSpaceStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
Send(*IndexSpaceResponse) error
}
type searchProviderIndexSpaceStream struct {
stream server.Stream
}
func (x *searchProviderIndexSpaceStream) Close() error {
return x.stream.Close()
}
func (x *searchProviderIndexSpaceStream) Context() context.Context {
return x.stream.Context()
}
func (x *searchProviderIndexSpaceStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *searchProviderIndexSpaceStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *searchProviderIndexSpaceStream) Send(m *IndexSpaceResponse) error {
return x.stream.Send(m)
func (h *searchProviderHandler) IndexSpace(ctx context.Context, in *IndexSpaceRequest, out *IndexSpaceResponse) error {
return h.SearchProviderHandler.IndexSpace(ctx, in, out)
}
// Api Endpoints for IndexProvider service
@@ -0,0 +1,346 @@
// Code generated by protoc-gen-microweb. DO NOT EDIT.
// source: v0.proto
package v0
import (
"bytes"
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/golang/protobuf/jsonpb"
merrors "go-micro.dev/v4/errors"
)
type webSearchProviderHandler struct {
r chi.Router
h SearchProviderHandler
}
func (h *webSearchProviderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.r.ServeHTTP(w, r)
}
func (h *webSearchProviderHandler) Search(w http.ResponseWriter, r *http.Request) {
req := &SearchRequest{}
resp := &SearchResponse{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusPreconditionFailed)
return
}
if err := h.h.Search(
r.Context(),
req,
resp,
); err != nil {
if merr, ok := merrors.As(err); ok && merr.Code == http.StatusNotFound {
http.Error(w, err.Error(), http.StatusNotFound)
} else {
http.Error(w, err.Error(), http.StatusBadRequest)
}
return
}
render.Status(r, http.StatusCreated)
render.JSON(w, r, resp)
}
func (h *webSearchProviderHandler) IndexSpace(w http.ResponseWriter, r *http.Request) {
req := &IndexSpaceRequest{}
resp := &IndexSpaceResponse{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusPreconditionFailed)
return
}
if err := h.h.IndexSpace(
r.Context(),
req,
resp,
); err != nil {
if merr, ok := merrors.As(err); ok && merr.Code == http.StatusNotFound {
http.Error(w, err.Error(), http.StatusNotFound)
} else {
http.Error(w, err.Error(), http.StatusBadRequest)
}
return
}
render.Status(r, http.StatusCreated)
render.JSON(w, r, resp)
}
func RegisterSearchProviderWeb(r chi.Router, i SearchProviderHandler, middlewares ...func(http.Handler) http.Handler) {
handler := &webSearchProviderHandler{
r: r,
h: i,
}
r.MethodFunc("POST", "/api/v0/search/search", handler.Search)
r.MethodFunc("POST", "/api/v0/search/index-space", handler.IndexSpace)
}
type webIndexProviderHandler struct {
r chi.Router
h IndexProviderHandler
}
func (h *webIndexProviderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.r.ServeHTTP(w, r)
}
func (h *webIndexProviderHandler) Search(w http.ResponseWriter, r *http.Request) {
req := &SearchIndexRequest{}
resp := &SearchIndexResponse{}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusPreconditionFailed)
return
}
if err := h.h.Search(
r.Context(),
req,
resp,
); err != nil {
if merr, ok := merrors.As(err); ok && merr.Code == http.StatusNotFound {
http.Error(w, err.Error(), http.StatusNotFound)
} else {
http.Error(w, err.Error(), http.StatusBadRequest)
}
return
}
render.Status(r, http.StatusCreated)
render.JSON(w, r, resp)
}
func RegisterIndexProviderWeb(r chi.Router, i IndexProviderHandler, middlewares ...func(http.Handler) http.Handler) {
handler := &webIndexProviderHandler{
r: r,
h: i,
}
r.MethodFunc("POST", "/api/v0/search/index/search", handler.Search)
}
// SearchRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of SearchRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchRequestJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *SearchRequest) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := SearchRequestJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*SearchRequest)(nil)
// SearchRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of SearchRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchRequestJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *SearchRequest) UnmarshalJSON(b []byte) error {
return SearchRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*SearchRequest)(nil)
// SearchResponseJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of SearchResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchResponseJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *SearchResponse) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := SearchResponseJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*SearchResponse)(nil)
// SearchResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of SearchResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchResponseJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *SearchResponse) UnmarshalJSON(b []byte) error {
return SearchResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*SearchResponse)(nil)
// SearchIndexRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of SearchIndexRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchIndexRequestJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *SearchIndexRequest) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := SearchIndexRequestJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*SearchIndexRequest)(nil)
// SearchIndexRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of SearchIndexRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchIndexRequestJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *SearchIndexRequest) UnmarshalJSON(b []byte) error {
return SearchIndexRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*SearchIndexRequest)(nil)
// SearchIndexResponseJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of SearchIndexResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchIndexResponseJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *SearchIndexResponse) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := SearchIndexResponseJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*SearchIndexResponse)(nil)
// SearchIndexResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of SearchIndexResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var SearchIndexResponseJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *SearchIndexResponse) UnmarshalJSON(b []byte) error {
return SearchIndexResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*SearchIndexResponse)(nil)
// IndexSpaceRequestJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of IndexSpaceRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var IndexSpaceRequestJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *IndexSpaceRequest) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := IndexSpaceRequestJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*IndexSpaceRequest)(nil)
// IndexSpaceRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of IndexSpaceRequest. This struct is safe to replace or modify but
// should not be done so concurrently.
var IndexSpaceRequestJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *IndexSpaceRequest) UnmarshalJSON(b []byte) error {
return IndexSpaceRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*IndexSpaceRequest)(nil)
// IndexSpaceResponseJSONMarshaler describes the default jsonpb.Marshaler used by all
// instances of IndexSpaceResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var IndexSpaceResponseJSONMarshaler = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *IndexSpaceResponse) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := IndexSpaceResponseJSONMarshaler.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*IndexSpaceResponse)(nil)
// IndexSpaceResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all
// instances of IndexSpaceResponse. This struct is safe to replace or modify but
// should not be done so concurrently.
var IndexSpaceResponseJSONUnmarshaler = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *IndexSpaceResponse) UnmarshalJSON(b []byte) error {
return IndexSpaceResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*IndexSpaceResponse)(nil)
@@ -34,22 +34,12 @@
"paths": {
"/api/v0/search/index-space": {
"post": {
"summary": "IndexSpace (re)indexes one or all spaces. The response is streamed, sending\nprogress information after each space has been indexed.",
"operationId": "SearchProvider_IndexSpace",
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"description": "A successful response.",
"schema": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/v0IndexSpaceResponse"
},
"error": {
"$ref": "#/definitions/rpcStatus"
}
},
"title": "Stream result of v0IndexSpaceResponse"
"$ref": "#/definitions/v0IndexSpaceResponse"
}
},
"default": {
@@ -342,39 +332,11 @@
},
"forceReindex": {
"type": "boolean"
},
"concurrency": {
"type": "integer",
"format": "int32"
}
}
},
"v0IndexSpaceResponse": {
"type": "object",
"properties": {
"spaceId": {
"type": "string",
"description": "The id of the space that has just been indexed."
},
"spaceDuration": {
"type": "string",
"description": "The duration it took to index this space."
},
"indexedSpaces": {
"type": "string",
"format": "int64",
"description": "The number of spaces that have been indexed so far."
},
"totalSpaces": {
"type": "string",
"format": "int64",
"description": "The total number of spaces that are being indexed."
},
"error": {
"type": "string",
"description": "Contains an error message in case indexing this particular space failed."
}
}
"type": "object"
},
"v0Match": {
"type": "object",
@@ -28,9 +28,7 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SearchProviderClient interface {
Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*SearchResponse, error)
// IndexSpace (re)indexes one or all spaces. The response is streamed, sending
// progress information after each space has been indexed.
IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IndexSpaceResponse], error)
IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (*IndexSpaceResponse, error)
}
type searchProviderClient struct {
@@ -51,33 +49,22 @@ func (c *searchProviderClient) Search(ctx context.Context, in *SearchRequest, op
return out, nil
}
func (c *searchProviderClient) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IndexSpaceResponse], error) {
func (c *searchProviderClient) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (*IndexSpaceResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &SearchProvider_ServiceDesc.Streams[0], SearchProvider_IndexSpace_FullMethodName, cOpts...)
out := new(IndexSpaceResponse)
err := c.cc.Invoke(ctx, SearchProvider_IndexSpace_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[IndexSpaceRequest, IndexSpaceResponse]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
return out, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type SearchProvider_IndexSpaceClient = grpc.ServerStreamingClient[IndexSpaceResponse]
// SearchProviderServer is the server API for SearchProvider service.
// All implementations must embed UnimplementedSearchProviderServer
// for forward compatibility.
type SearchProviderServer interface {
Search(context.Context, *SearchRequest) (*SearchResponse, error)
// IndexSpace (re)indexes one or all spaces. The response is streamed, sending
// progress information after each space has been indexed.
IndexSpace(*IndexSpaceRequest, grpc.ServerStreamingServer[IndexSpaceResponse]) error
IndexSpace(context.Context, *IndexSpaceRequest) (*IndexSpaceResponse, error)
mustEmbedUnimplementedSearchProviderServer()
}
@@ -91,8 +78,8 @@ type UnimplementedSearchProviderServer struct{}
func (UnimplementedSearchProviderServer) Search(context.Context, *SearchRequest) (*SearchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Search not implemented")
}
func (UnimplementedSearchProviderServer) IndexSpace(*IndexSpaceRequest, grpc.ServerStreamingServer[IndexSpaceResponse]) error {
return status.Error(codes.Unimplemented, "method IndexSpace not implemented")
func (UnimplementedSearchProviderServer) IndexSpace(context.Context, *IndexSpaceRequest) (*IndexSpaceResponse, error) {
return nil, status.Error(codes.Unimplemented, "method IndexSpace not implemented")
}
func (UnimplementedSearchProviderServer) mustEmbedUnimplementedSearchProviderServer() {}
func (UnimplementedSearchProviderServer) testEmbeddedByValue() {}
@@ -133,17 +120,24 @@ func _SearchProvider_Search_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler)
}
func _SearchProvider_IndexSpace_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(IndexSpaceRequest)
if err := stream.RecvMsg(m); err != nil {
return err
func _SearchProvider_IndexSpace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(IndexSpaceRequest)
if err := dec(in); err != nil {
return nil, err
}
return srv.(SearchProviderServer).IndexSpace(m, &grpc.GenericServerStream[IndexSpaceRequest, IndexSpaceResponse]{ServerStream: stream})
if interceptor == nil {
return srv.(SearchProviderServer).IndexSpace(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SearchProvider_IndexSpace_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SearchProviderServer).IndexSpace(ctx, req.(*IndexSpaceRequest))
}
return interceptor(ctx, in, info, handler)
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type SearchProvider_IndexSpaceServer = grpc.ServerStreamingServer[IndexSpaceResponse]
// SearchProvider_ServiceDesc is the grpc.ServiceDesc for SearchProvider service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -155,14 +149,12 @@ var SearchProvider_ServiceDesc = grpc.ServiceDesc{
MethodName: "Search",
Handler: _SearchProvider_Search_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "IndexSpace",
Handler: _SearchProvider_IndexSpace_Handler,
ServerStreams: true,
MethodName: "IndexSpace",
Handler: _SearchProvider_IndexSpace_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "opencloud/services/search/v0/search.proto",
}
+1 -3
View File
@@ -31,9 +31,7 @@ plugins:
opencloud.services.eventhistory.v0;\
opencloud.messages.eventhistory.v0;\
opencloud.services.policies.v0;\
opencloud.messages.policies.v0;\
opencloud.services.search.v0;\
opencloud.messages.search.v0"
opencloud.messages.policies.v0"
- name: openapiv2
path: ../../.bingo/protoc-gen-openapiv2
@@ -9,7 +9,6 @@ import "protoc-gen-openapiv2/options/annotations.proto";
import "google/api/field_behavior.proto";
import "google/api/annotations.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/duration.proto";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
info: {
@@ -42,9 +41,7 @@ service SearchProvider {
body: "*"
};
};
// IndexSpace (re)indexes one or all spaces. The response is streamed, sending
// progress information after each space has been indexed.
rpc IndexSpace(IndexSpaceRequest) returns (stream IndexSpaceResponse) {
rpc IndexSpace(IndexSpaceRequest) returns (IndexSpaceResponse) {
option (google.api.http) = {
post: "/api/v0/search/index-space",
body: "*"
@@ -108,18 +105,7 @@ message IndexSpaceRequest {
string space_id = 1;
string user_id = 2;
bool force_reindex = 3;
int32 concurrency = 4 [(google.api.field_behavior) = OPTIONAL];
}
message IndexSpaceResponse {
// The id of the space that has just been indexed.
string space_id = 1;
// The duration it took to index this space.
google.protobuf.Duration space_duration = 2;
// The number of spaces that have been indexed so far.
int64 indexed_spaces = 3;
// The total number of spaces that are being indexed.
int64 total_spaces = 4;
// Contains an error message in case indexing this particular space failed.
string error = 5;
}
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jörn Friedrich Dreyer <jfd@butonic.de>, 2025\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Efstathios Iosifidis <eiosifidis@gmail.com>, 2026\n"
"Language-Team: Greek (https://app.transifex.com/opencloud-eu/teams/204053/el/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Elías Martín, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/opencloud-eu/teams/204053/es/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: eric_G <junk.eg@free.fr>, 2025\n"
"Language-Team: French (https://app.transifex.com/opencloud-eu/teams/204053/fr/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: mitibor, 2026\n"
"Language-Team: Hungarian (https://app.transifex.com/opencloud-eu/teams/204053/hu/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Simone Broglia, 2025\n"
"Language-Team: Italian (https://app.transifex.com/opencloud-eu/teams/204053/it/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: iikaka88, 2025\n"
"Language-Team: Japanese (https://app.transifex.com/opencloud-eu/teams/204053/ja/)\n"
@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: 4580f07cef35810b72f8a1e8fd521c9a_6684a19 <07c3e3571dc5eebd81f2c3a10488f503_1171750>, 2025\n"
"Language-Team: Korean (https://app.transifex.com/opencloud-eu/teams/204053/ko/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: BoneNI, 2026\n"
"Language-Team: Lao (https://app.transifex.com/opencloud-eu/teams/204053/lo/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"
@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Matt, 2026\n"
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Mário Machado, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"
@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Lulufox, 2025\n"
"Language-Team: Russian (https://app.transifex.com/opencloud-eu/teams/204053/ru/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>, 2025\n"
"Language-Team: Swedish (https://app.transifex.com/opencloud-eu/teams/204053/sv/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Quan Tran, 2025\n"
"Language-Team: Vietnamese (https://app.transifex.com/opencloud-eu/teams/204053/vi/)\n"
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-08 23:16+0000\n"
"POT-Creation-Date: 2026-07-19 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: YQS Yang, 2025\n"
"Language-Team: Chinese (https://app.transifex.com/opencloud-eu/teams/204053/zh/)\n"
+1 -3
View File
@@ -661,10 +661,8 @@ func (a *ActivitylogService) removeCachedParentID(ref *provider.Reference) {
}
purgeId = info.GetId()
}
// The parent id cache is populated lazily and its entries expire, so a
// missing key is the expected case rather than an error.
if err := a.parentIdCache.Remove(storagespace.FormatResourceID(purgeId)); err != nil {
a.log.Debug().Interface("event", ref).Err(err).Msg("could not delete parent id cache")
a.log.Error().Interface("event", ref).Err(err).Msg("could not delete parent id cache")
}
}
@@ -1,7 +1,6 @@
package service
import (
"bytes"
"context"
"net"
"os"
@@ -14,10 +13,8 @@ import (
nserver "github.com/nats-io/nats-server/v2/server"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/activitylog/pkg/config"
eventsmocks "github.com/opencloud-eu/reva/v2/pkg/events/mocks"
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
"github.com/test-go/testify/mock"
"go.opentelemetry.io/otel/trace/noop"
)
@@ -268,42 +265,6 @@ var _ = Describe("ActivitylogService", func() {
})
})
})
Describe("removeCachedParentID", func() {
var logBuffer *bytes.Buffer
newLoggerAtLevel := func(level string) log.Logger {
logBuffer = &bytes.Buffer{}
return log.Logger{Logger: log.NewLogger(log.Level(level)).Output(logBuffer)}
}
It("does not log an error when the entry was never cached", func() {
alog.log = newLoggerAtLevel("error")
alog.removeCachedParentID(reference("never-cached"))
Expect(logBuffer.String()).To(BeEmpty())
})
It("logs a missing entry at debug level", func() {
alog.log = newLoggerAtLevel("debug")
alog.removeCachedParentID(reference("never-cached"))
Expect(logBuffer.String()).To(ContainSubstring("could not delete parent id cache"))
Expect(logBuffer.String()).To(ContainSubstring(`"level":"debug"`))
})
It("does not log at all when the entry was cached", func() {
alog.log = newLoggerAtLevel("debug")
ref := reference("cached")
Expect(alog.parentIdCache.Set(storagespace.FormatResourceID(ref.GetResourceId()), resourceID("parent"))).To(Succeed())
alog.removeCachedParentID(ref)
Expect(logBuffer.String()).To(BeEmpty())
})
})
})
func activitites(acts ...any) []RawActivity {
+1 -1
View File
@@ -43,7 +43,7 @@ func Server(cfg *config.Config) *cobra.Command {
{
svc, err := service.NewAntivirus(cfg, logger, traceProvider)
if err != nil {
logger.Error().Err(err).Str("server", "antivirus").Msg("Failed to initialize antivirus service")
fmt.Errorf("failed to initialize antivirus service: %v", err)
os.Exit(1)
}
-2
View File
@@ -2,7 +2,6 @@ package config
import (
"context"
"time"
"github.com/opencloud-eu/opencloud/pkg/shared"
)
@@ -73,7 +72,6 @@ type LDAPProvider struct {
LdapDisabledUsersGroupDN string `yaml:"ldap_disabled_users_group_dn" env:"OC_LDAP_DISABLED_USERS_GROUP_DN;AUTH_BASIC_DISABLED_USERS_GROUP_DN" desc:"The distinguished name of the group to which added users will be classified as disabled when 'disable_user_mechanism' is set to 'group'." introductionVersion:"1.0.0"`
UserSchema LDAPUserSchema `yaml:"user_schema"`
GroupSchema LDAPGroupSchema `yaml:"group_schema"`
LookupCacheTTL time.Duration `yaml:"lookup_cache_ttl" env:"OC_LDAP_LOOKUP_CACHE_TTL;AUTH_BASIC_LDAP_LOOKUP_CACHE_TTL" desc:"The time to live for the in-memory cache of LDAP lookups. This cache is used to reduce the number of LDAP queries for user and group lookups." introductionVersion:"7.5.0"`
}
type LDAPUserSchema struct {
@@ -1,8 +1,6 @@
package defaults
import (
"time"
"github.com/opencloud-eu/opencloud/pkg/shared"
"github.com/opencloud-eu/opencloud/pkg/structs"
"github.com/opencloud-eu/opencloud/services/auth-basic/pkg/config"
@@ -66,7 +64,6 @@ func DefaultConfig() *config.Config {
Groupname: "cn",
Member: "member",
},
LookupCacheTTL: 10 * time.Second,
},
JSON: config.JSONProvider{},
OwnCloudSQL: config.OwnCloudSQLProvider{
@@ -92,6 +92,5 @@ func ldapConfigFromString(cfg config.LDAPProvider) map[string]any {
"groupName": cfg.GroupSchema.Groupname,
"member": cfg.GroupSchema.Member,
},
"lookup_cache_ttl": cfg.LookupCacheTTL,
}
}
-2
View File
@@ -48,8 +48,6 @@ var _registeredEvents = []events.Unmarshaller{
events.LinkUpdated{},
events.LinkRemoved{},
events.BackchannelLogout{},
events.LabelAdded{},
events.LabelRemoved{},
}
// Server is the entrypoint for the server command.
-27
View File
@@ -132,11 +132,6 @@ func (cl *ClientlogService) processEvent(event events.Event) {
users, data, err = processShareEvent(ctx, ref, gwc, event.InitiatorID, uid, gid)
}
labelEv := func(typ string, ref *provider.Reference, uid *user.UserId) {
evType = typ
users, data, err = processLabelEvent(ctx, ref, gwc, event.InitiatorID, uid)
}
spaceEv := func(typ string, id *provider.StorageSpaceId, uids []string) {
evType = typ
users, data, err = processSpaceEvent(ctx, id, gwc, event.InitiatorID, uids)
@@ -171,10 +166,6 @@ func (cl *ClientlogService) processEvent(event events.Event) {
fileEv("file-unlocked", e.Ref)
case events.FileTouched:
fileEv("file-touched", e.Ref)
case events.LabelAdded:
labelEv("item-favorite-added", e.Ref, e.UserID)
case events.LabelRemoved:
labelEv("item-favorite-removed", e.Ref, e.UserID)
case events.SpaceCreated:
spaceEv("space-created", e.ID, []string{e.Executant.GetOpaqueId()})
case events.SpaceDisabled:
@@ -264,24 +255,6 @@ func processFileEvent(ctx context.Context, ref *provider.Reference, gwc gateway.
return users, data, err
}
// process label (e.g. favorite) related events, notifying only the user the label belongs to
func processLabelEvent(ctx context.Context, ref *provider.Reference, gwc gateway.GatewayAPIClient, initiatorid string, uid *user.UserId) ([]string, FileEvent, error) {
info, err := utils.GetResource(ctx, ref, gwc)
if err != nil {
return nil, FileEvent{}, err
}
data := FileEvent{
ParentItemID: storagespace.FormatResourceID(info.GetParentId()),
ItemID: storagespace.FormatResourceID(info.GetId()),
SpaceID: storagespace.FormatStorageID(info.GetSpace().GetRoot().GetStorageId(), info.GetSpace().GetRoot().GetSpaceId()),
InitiatorID: initiatorid,
Etag: info.GetEtag(),
}
return []string{uid.GetOpaqueId()}, data, nil
}
// process share related events
func processShareEvent(ctx context.Context, ref *provider.Reference, gwc gateway.GatewayAPIClient, initiatorid string, shareeID *user.UserId, shareeGroupID *group.GroupId) ([]string, FileEvent, error) {
users, data, err := processFileEvent(ctx, ref, gwc, initiatorid)
@@ -14,7 +14,8 @@ import (
type Permission string
const (
PermissionCollaborationManageFonts Permission = "Collaboration.Fonts.Manage"
PermissionCollaborationManageFonts Permission = "Collaboration.Fonts.Manage"
PermissionCollaborationPublishNotification Permission = "Collaboration.Notification.Publish"
)
func CheckPermissions(gatewayClient gateway.GatewayAPIClient, ctx context.Context, permission Permission) (*userpb.User, bool, error) {
+29 -2
View File
@@ -8,6 +8,7 @@ import (
"os/signal"
"time"
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
"github.com/opencloud-eu/reva/v2/pkg/store"
"github.com/spf13/afero"
@@ -16,6 +17,7 @@ import (
microstore "go-micro.dev/v4/store"
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
"github.com/opencloud-eu/opencloud/pkg/generators"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/registry"
"github.com/opencloud-eu/opencloud/pkg/runner"
@@ -26,6 +28,7 @@ import (
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/connector"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/font"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/helpers"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/notification"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/server/debug"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/server/grpc"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/server/http"
@@ -171,8 +174,32 @@ func Server(cfg *config.Config) *cobra.Command {
}
}
var optionalHTTPServerOptions []http.Option
var notificationService notification.Service
if cfg.Events.Endpoint == "" {
logger.Warn().Msg("Events endpoint is not configured, notifications from the collaboration service will not work")
} else {
connName := generators.GenerateConnectionName(cfg.Service.Name, generators.NTypeBus)
natsStream, err := stream.NatsFromConfig(connName, true, stream.NatsConfig(cfg.Events))
if err != nil {
return err
}
notificationService, err = notification.NewService(
notification.ServiceOptions{}.
WithLogger(logger).
WithGatewaySelector(gatewaySelector).
WithEventPublisher(natsStream).
WithMachineAuthAPIKey(cfg.MachineAuthAPIKey),
)
if err != nil {
return err
}
optionalHTTPServerOptions = append(optionalHTTPServerOptions, http.NotificationService(&notificationService))
}
// start HTTP server
httpServer, err := http.Server(
httpServer, err := http.Server(append([]http.Option{
http.Adapter(connector.NewHttpAdapter(gatewaySelector, cfg, st, selector.NewSelector(selector.Registry(registry.GetRegistry())))),
http.Logger(logger),
http.Config(cfg),
@@ -180,7 +207,7 @@ func Server(cfg *config.Config) *cobra.Command {
http.TracerProvider(traceProvider),
http.Store(st),
http.FontService(fontService),
)
}, optionalHTTPServerOptions...)...)
if err != nil {
logger.Info().Err(err).Str("transport", "http").Msg("Failed to initialize server")
return err
@@ -14,6 +14,7 @@ type Config struct {
App App `yaml:"app"`
Font Font `yaml:"font"`
Store Store `yaml:"store"`
Events Events `yaml:"events"`
TokenManager *TokenManager `yaml:"token_manager"`
@@ -27,4 +28,6 @@ type Config struct {
Debug Debug `yaml:"debug"`
Context context.Context `yaml:"-"`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY;COLLABORATION_MACHINE_AUTH_API_KEY" desc:"The machine auth API key used to validate internal requests necessary to access resources from other services." introductionVersion:"7.3.0"`
}
@@ -39,6 +39,10 @@ func DefaultConfig() *config.Config {
AssetPath: filepath.Join(defaults.BaseDataPath(), "collaboration/fonts"),
PreviewText: "OpenCloud",
},
Events: config.Events{
Endpoint: "127.0.0.1:9233",
Cluster: "opencloud-cluster",
},
Store: config.Store{
Store: "nats-js-kv",
Nodes: []string{"127.0.0.1:9233"},
@@ -92,6 +96,10 @@ func EnsureDefaults(cfg *config.Config) {
if cfg.CS3Api.GRPCClientTLS == nil && cfg.Commons != nil {
cfg.CS3Api.GRPCClientTLS = structs.CopyOrZeroValue(cfg.Commons.GRPCClientTLS)
}
if cfg.MachineAuthAPIKey == "" && cfg.Commons != nil && cfg.Commons.MachineAuthAPIKey != "" {
cfg.MachineAuthAPIKey = cfg.Commons.MachineAuthAPIKey
}
}
// Sanitize sanitized the configuration
@@ -0,0 +1,12 @@
package config
// Events combines the configuration options for the event bus.
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;COLLABORATION_EVENTS_ENDPOINT" desc:"The address of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture." introductionVersion:"7.3.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;COLLABORATION_EVENTS_CLUSTER" desc:"The clusterID of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture. Mandatory when using NATS as event system." introductionVersion:"7.3.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;COLLABORATION_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"7.3.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;COLLABORATION_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided COLLABORATION_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"7.3.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;COLLABORATION_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"7.3.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;COLLABORATION_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"7.3.0"`
AuthPassword string `yaml:"password" env:"OC_EVENTS_AUTH_PASSWORD;COLLABORATION_EVENTS_AUTH_PASSWORD" desc:"The password to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"7.3.0"`
}
@@ -27,18 +27,17 @@ import (
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/golang/protobuf/proto"
"github.com/google/uuid"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/connector/fileinfo"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/helpers"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/middleware"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/wopisrc"
ctxpkg "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
"github.com/opencloud-eu/reva/v2/pkg/utils"
"github.com/rs/zerolog"
microstore "go-micro.dev/v4/store"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/connector/fileinfo"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/helpers"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/middleware"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/wopisrc"
)
const (
@@ -1579,6 +1578,7 @@ func (f *FileConnector) GetAvatar(ctx context.Context, userID string) (*Connecto
}
return nil, NewConnectorError(http.StatusBadGateway, "failed to fetch avatar")
}
defer photoFile.Close()
data, err := io.ReadAll(photoFile)
if err != nil {
@@ -0,0 +1,10 @@
package notification
import (
"github.com/go-playground/validator/v10"
)
var validate = validator.New(
validator.WithPrivateFieldValidation(),
validator.WithRequiredStructEnabled(),
)
@@ -0,0 +1,153 @@
package notification
import (
"context"
"encoding/json"
"io"
"net/http"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
"google.golang.org/grpc/metadata"
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/collaboration"
)
type ServiceOptions struct {
logger log.Logger `validate:"required"`
eventPublisher events.Publisher `validate:"required"`
gatewaySelector pool.Selectable[gateway.GatewayAPIClient] `validate:"required"`
machineAuthAPIKey string `validate:"required,min=1"`
}
func (o ServiceOptions) WithLogger(logger log.Logger) ServiceOptions {
o.logger = logger
return o
}
func (o ServiceOptions) WithEventPublisher(eventPublisher events.Publisher) ServiceOptions {
o.eventPublisher = eventPublisher
return o
}
func (o ServiceOptions) WithMachineAuthAPIKey(key string) ServiceOptions {
o.machineAuthAPIKey = key
return o
}
func (o ServiceOptions) WithGatewaySelector(gws pool.Selectable[gateway.GatewayAPIClient]) ServiceOptions {
o.gatewaySelector = gws
return o
}
type Service struct {
log log.Logger
eventPublisher events.Publisher
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
machineAuthAPIKey string
}
func NewService(options ServiceOptions) (Service, error) {
if err := validate.Struct(options); err != nil {
return Service{}, err
}
return Service{
log: options.logger,
eventPublisher: options.eventPublisher,
gatewaySelector: options.gatewaySelector,
machineAuthAPIKey: options.machineAuthAPIKey,
}, nil
}
func (s Service) HandleNotification(w http.ResponseWriter, r *http.Request) {
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
requestUser, canManage, err := collaboration.CheckPermissions(gatewayClient, r.Context(), collaboration.PermissionCollaborationPublishNotification)
switch {
case err != nil:
w.WriteHeader(http.StatusInternalServerError)
return
case !canManage:
w.WriteHeader(http.StatusForbidden)
return
}
defer func() { _ = r.Body.Close() }()
body, err := io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
var data = struct {
Type string `json:"type" validate:"required"`
UserIDs []string `json:"userIDs" validate:"required"`
FileID string `json:"fileID" validate:"required"`
}{}
if err := json.Unmarshal(body, &data); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := validate.Struct(data); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
event := ocEvents.ResourceMention{
Executant: requestUser.GetId(),
Timestamp: time.Now(),
}
for _, userID := range data.UserIDs {
authResponse, err := gatewayClient.Authenticate(context.Background(), &gateway.AuthenticateRequest{
Type: "machine",
ClientId: "userid:" + userID,
ClientSecret: s.machineAuthAPIKey,
})
if err != nil || authResponse.Status.Code != rpcv1beta1.Code_CODE_OK {
w.WriteHeader(http.StatusInternalServerError)
return
}
resourceID, err := storagespace.ParseID(data.FileID)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
statResponse, err := gatewayClient.Stat(
metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, authResponse.GetToken()),
&storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: &resourceID}},
)
if err != nil || statResponse.Status.Code != rpcv1beta1.Code_CODE_OK {
w.WriteHeader(http.StatusInternalServerError)
return
}
event.UserIDs = append(event.UserIDs, authResponse.User.GetId())
event.Ref = &storageprovider.Reference{
ResourceId: statResponse.GetInfo().GetId(),
}
}
if err := events.Publish(r.Context(), s.eventPublisher, event); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
@@ -10,6 +10,7 @@ import (
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/connector"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/font"
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/notification"
)
// Option defines a single option function.
@@ -17,13 +18,14 @@ type Option func(o *Options)
// Options define the available options for this package.
type Options struct {
Adapter *connector.HttpAdapter
Logger log.Logger
Context context.Context
Config *config.Config
TracerProvider trace.TracerProvider
Store microstore.Store
FontService font.Service
Adapter *connector.HttpAdapter
Logger log.Logger
Context context.Context
Config *config.Config
TracerProvider trace.TracerProvider
Store microstore.Store
FontService font.Service
NotificationService *notification.Service
}
// newOptions initializes the available default options.
@@ -85,3 +87,10 @@ func FontService(val font.Service) Option {
o.FontService = val
}
}
// NotificationService provides a function to set the NotificationService option
func NotificationService(val *notification.Service) Option {
return func(o *Options) {
o.NotificationService = val
}
}
@@ -22,6 +22,10 @@ import (
func Server(opts ...Option) (http.Service, error) {
options := newOptions(opts...)
if options.NotificationService == nil {
options.Logger.Warn().Msg("running without notification service: no notifications will be sent, set the events endpoint to enable them")
}
service, err := http.NewService(
http.TLSConfig(options.Config.HTTP.TLS),
http.Logger(options.Logger),
@@ -96,6 +100,7 @@ func Server(opts ...Option) (http.Service, error) {
// prepareRoutes will prepare all the implemented routes
func prepareRoutes(r *chi.Mux, options Options) {
fontService := options.FontService
notificationService := options.NotificationService
adapter := options.Adapter
logger := options.Logger
// prepare basic logger for the request
@@ -227,5 +232,11 @@ func prepareRoutes(r *chi.Mux, options Options) {
r.Delete("/{id}", fontService.DeleteFont)
})
})
if notificationService != nil { // optional
r.With(auth).Route("/notify", func(r chi.Router) {
r.Post("/", notificationService.HandleNotification)
})
}
})
}
+34 -51
View File
@@ -6,19 +6,18 @@ import (
"os/signal"
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
"github.com/opencloud-eu/opencloud/pkg/generators"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/runner"
ogrpc "github.com/opencloud-eu/opencloud/pkg/service/grpc"
"github.com/opencloud-eu/opencloud/pkg/tracing"
"github.com/opencloud-eu/opencloud/pkg/version"
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config/parser"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/metrics"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/server/consumer"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/server/debug"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/server/grpc"
svc "github.com/opencloud-eu/opencloud/services/eventhistory/pkg/service"
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
"github.com/opencloud-eu/reva/v2/pkg/store"
"github.com/spf13/cobra"
@@ -59,6 +58,12 @@ func Server(cfg *config.Config) *cobra.Command {
gr := runner.NewGroup()
connName := generators.GenerateConnectionName(cfg.Service.Name, generators.NTypeBus)
consumer, err := stream.NatsFromConfig(connName, false, stream.NatsConfig(cfg.Events))
if err != nil {
return err
}
st := store.Create(
store.Store(cfg.Store.Store),
store.TTL(cfg.Store.TTL),
@@ -71,56 +76,34 @@ func Server(cfg *config.Config) *cobra.Command {
store.TLSRootCA(cfg.Store.TLSRootCACertificate),
)
if !cfg.Events.Disabled {
_, err = consumer.NewConsumer(
consumer.Logger(logger),
consumer.Config(cfg),
consumer.Persistence(st),
)
if err != nil {
return err
}
} else {
logger.Info().Msg("event listening disabled, not starting event consumer")
}
if !cfg.GRPC.Disabled {
eh, err := svc.NewEventHistoryService(cfg, st, logger)
if err != nil {
return err
}
service := grpc.NewService(
grpc.Logger(logger),
grpc.Context(ctx),
grpc.Config(cfg),
grpc.Name(cfg.Service.Name),
grpc.Namespace(cfg.GRPC.Namespace),
grpc.Address(cfg.GRPC.Addr),
grpc.Metrics(m),
grpc.TraceProvider(traceProvider),
)
if err := ehsvc.RegisterEventHistoryServiceHandler(service.Server(), eh); err != nil {
return err
}
gr.Add(runner.NewGoMicroGrpcServerRunner(cfg.Service.Name+".grpc", service))
} else {
logger.Info().Msg("gRPC server disabled, not starting gRPC service")
}
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
service := grpc.NewService(
grpc.Logger(logger),
grpc.Context(ctx),
grpc.Config(cfg),
grpc.Name(cfg.Service.Name),
grpc.Namespace(cfg.GRPC.Namespace),
grpc.Address(cfg.GRPC.Addr),
grpc.Metrics(m),
grpc.Consumer(consumer),
grpc.Persistence(st),
grpc.TraceProvider(traceProvider),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(runner.NewGolangHttpServerRunner(cfg.Service.Name+".debug", debugServer))
gr.Add(runner.NewGoMicroGrpcServerRunner(cfg.Service.Name+".grpc", service))
{
debugServer, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(runner.NewGolangHttpServerRunner(cfg.Service.Name+".debug", debugServer))
}
grResults := gr.Run(ctx)
@@ -32,7 +32,6 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"EVENTHISTORY_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"1.0.0"`
Namespace string `yaml:"-"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Disabled bool `yaml:"disabled" env:"EVENTHISTORY_GRPC_DISABLED" desc:"Disables the GRPC service. Set this to true if the service should only handle events." introductionVersion:"7.5.0"`
}
// Store configures the store to use
@@ -58,5 +57,4 @@ type Events struct {
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;EVENTHISTORY_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;EVENTHISTORY_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthPassword string `yaml:"password" env:"OC_EVENTS_AUTH_PASSWORD;EVENTHISTORY_EVENTS_AUTH_PASSWORD" desc:"The password to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
Disabled bool `yaml:"disabled" env:"EVENTHISTORY_EVENTS_DISABLED" desc:"Disables listening for events. Set this to true if the service should only handle GRPC requests." introductionVersion:"7.5.0"`
}
@@ -4,7 +4,6 @@ import (
"errors"
occfg "github.com/opencloud-eu/opencloud/pkg/config"
"github.com/opencloud-eu/opencloud/pkg/shared"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config/defaults"
@@ -35,9 +34,5 @@ func ParseConfig(cfg *config.Config) error {
// Validate validates the config
func Validate(cfg *config.Config) error {
if cfg.Events.Disabled && cfg.GRPC.Disabled {
return shared.AllComponentsDisabledError(cfg.Service.Name)
}
return nil
}
@@ -1,58 +0,0 @@
package consumer
import (
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
"github.com/opencloud-eu/reva/v2/pkg/events"
"go-micro.dev/v4/store"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Config *config.Config
Persistence store.Store
Consumer events.Consumer
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
// Persistence provides a function to configure the store
func Persistence(store store.Store) Option {
return func(o *Options) {
o.Persistence = store
}
}
// Stream provides a function to set the event source to consume from.
func Stream(consumer events.Consumer) Option {
return func(o *Options) {
o.Consumer = consumer
}
}
@@ -1,81 +0,0 @@
package consumer
import (
"encoding/json"
"github.com/opencloud-eu/opencloud/pkg/generators"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
svc "github.com/opencloud-eu/opencloud/services/eventhistory/pkg/service"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
"go-micro.dev/v4/store"
)
// Consumer consumes all events and stores them in the store
type Consumer struct {
ch <-chan events.Event
store store.Store
cfg *config.Config
log log.Logger
}
// NewConsumer initializes the event consumer and starts storing events
func NewConsumer(opts ...Option) (*Consumer, error) {
options := newOptions(opts...)
cons := options.Consumer
if cons == nil {
connName := generators.GenerateConnectionName(options.Config.Service.Name, generators.NTypeBus)
var err error
cons, err = stream.NatsFromConfig(connName, false, stream.NatsConfig{
Endpoint: options.Config.Events.Endpoint,
Cluster: options.Config.Events.Cluster,
TLSInsecure: options.Config.Events.TLSInsecure,
TLSRootCACertificate: options.Config.Events.TLSRootCACertificate,
EnableTLS: options.Config.Events.EnableTLS,
AuthUsername: options.Config.Events.AuthUsername,
AuthPassword: options.Config.Events.AuthPassword,
})
if err != nil {
return nil, err
}
}
ch, err := events.ConsumeAll(cons, "evhistory")
if err != nil {
return nil, err
}
c := &Consumer{ch: ch, store: options.Persistence, cfg: options.Config, log: options.Logger}
go c.StoreEvents()
return c, nil
}
// StoreEvents consumes all events and stores them in the store. Will block
func (c *Consumer) StoreEvents() {
for event := range c.ch {
ev, err := json.Marshal(svc.StoreEvent{
ID: event.ID,
Type: event.Type,
Event: event.Event.([]byte),
})
if err != nil {
c.log.Error().Err(err).Str("eventid", event.ID).Msg("could not marshal event")
continue
}
if err := c.store.Write(&store.Record{
Key: event.ID,
Value: ev,
Expiry: c.cfg.Store.TTL,
Metadata: map[string]any{
"type": event.Type,
},
}); err != nil {
// we can't store. That's it for us.
c.log.Error().Err(err).Str("eventid", event.ID).Msg("could not store event")
continue
}
}
}
@@ -6,6 +6,8 @@ import (
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/metrics"
"github.com/opencloud-eu/reva/v2/pkg/events"
"go-micro.dev/v4/store"
"go.opentelemetry.io/otel/trace"
)
@@ -21,6 +23,8 @@ type Options struct {
Config *config.Config
Metrics *metrics.Metrics
Namespace string
Persistence store.Store
Consumer events.Consumer
TraceProvider trace.TracerProvider
}
@@ -84,6 +88,20 @@ func Namespace(val string) Option {
}
}
// Persistence provides a function to configure the store
func Persistence(store store.Store) Option {
return func(o *Options) {
o.Persistence = store
}
}
// Consumer provides a function to configure the consumer
func Consumer(consumer events.Consumer) Option {
return func(o *Options) {
o.Consumer = consumer
}
}
// TraceProvider provides a function to configure the trace provider
func TraceProvider(traceProvider trace.TracerProvider) Option {
return func(o *Options) {
@@ -3,6 +3,8 @@ package grpc
import (
"github.com/opencloud-eu/opencloud/pkg/service/grpc"
"github.com/opencloud-eu/opencloud/pkg/version"
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
svc "github.com/opencloud-eu/opencloud/services/eventhistory/pkg/service"
)
// NewService initializes the grpc service and server.
@@ -30,5 +32,16 @@ func NewService(opts ...Option) grpc.Service {
return grpc.Service{}
}
eh, err := svc.NewEventHistoryService(options.Config, options.Consumer, options.Persistence, options.Logger)
if err != nil {
options.Logger.Fatal().Err(err).Msg("Error creating event history service")
return grpc.Service{}
}
_ = ehsvc.RegisterEventHistoryServiceHandler(
service.Server(),
eh,
)
return service
}
+43 -2
View File
@@ -11,6 +11,7 @@ import (
ehmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/eventhistory/v0"
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
"github.com/opencloud-eu/reva/v2/pkg/events"
"go-micro.dev/v4/store"
)
@@ -23,14 +24,54 @@ type StoreEvent struct {
// EventHistoryService is the service responsible for event history
type EventHistoryService struct {
ch <-chan events.Event
store store.Store
cfg *config.Config
log log.Logger
}
// NewEventHistoryService returns an EventHistory service
func NewEventHistoryService(cfg *config.Config, store store.Store, log log.Logger) (*EventHistoryService, error) {
return &EventHistoryService{store: store, cfg: cfg, log: log}, nil
func NewEventHistoryService(cfg *config.Config, consumer events.Consumer, store store.Store, log log.Logger) (*EventHistoryService, error) {
if consumer == nil || store == nil {
return nil, fmt.Errorf("need non nil consumer (%v) and store (%v) to work properly", consumer, store)
}
ch, err := events.ConsumeAll(consumer, "evhistory")
if err != nil {
return nil, err
}
eh := &EventHistoryService{ch: ch, store: store, cfg: cfg, log: log}
go eh.StoreEvents()
return eh, nil
}
// StoreEvents consumes all events and stores them in the store. Will block
func (eh *EventHistoryService) StoreEvents() {
for event := range eh.ch {
ev, err := json.Marshal(StoreEvent{
ID: event.ID,
Type: event.Type,
Event: event.Event.([]byte),
})
if err != nil {
eh.log.Error().Err(err).Str("eventid", event.ID).Msg("could not marshal event")
continue
}
if err := eh.store.Write(&store.Record{
Key: event.ID,
Value: ev,
Expiry: eh.cfg.Store.TTL,
Metadata: map[string]any{
"type": event.Type,
},
}); err != nil {
// we can't store. That's it for us.
eh.log.Error().Err(err).Str("eventid", event.ID).Msg("could not store event")
continue
}
}
}
// GetEvents allows retrieving events from the eventstore by id
+55 -105
View File
@@ -14,7 +14,6 @@ import (
"github.com/opencloud-eu/opencloud/pkg/log"
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/config"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/server/consumer"
"github.com/opencloud-eu/opencloud/services/eventhistory/pkg/service"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/store"
@@ -35,121 +34,72 @@ var _ = Describe("EventHistoryService", func() {
BeforeEach(func() {
var err error
sto = store.Create()
eh, err = service.NewEventHistoryService(cfg, sto, log.Logger{})
Expect(err).ToNot(HaveOccurred())
})
Context("with event consumer", func() {
BeforeEach(func() {
bus = testBus(make(chan events.Event))
_, err := consumer.NewConsumer(
consumer.Logger(log.Logger{}),
consumer.Config(cfg),
consumer.Persistence(sto),
consumer.Stream(bus),
)
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
close(bus)
})
It("Records events, stores them and allows them to be retrieved", func() {
id := bus.Publish(events.UploadReady{})
// service will store eventually
time.Sleep(500 * time.Millisecond)
resp := &ehsvc.GetEventsResponse{}
err := eh.GetEvents(context.Background(), &ehsvc.GetEventsRequest{Ids: []string{id}}, resp)
Expect(err).ToNot(HaveOccurred())
Expect(resp).ToNot(BeNil())
Expect(len(resp.Events)).To(Equal(1))
Expect(resp.Events[0].Id).To(Equal(id))
})
It("Gets all events", func() {
ids := make([]string, 3)
ids[0] = bus.Publish(events.UploadReady{
ExecutingUser: &userv1beta1.User{
Id: &userv1beta1.UserId{
OpaqueId: "test-id",
},
},
Failed: false,
Timestamp: utils.TimeToTS(time.Time{}),
})
ids[1] = bus.Publish(events.UserCreated{
UserID: "another-id",
})
ids[2] = bus.Publish(events.UserDeleted{
Executant: &userv1beta1.UserId{
OpaqueId: "another-id",
},
UserID: "test-id",
})
time.Sleep(500 * time.Millisecond)
resp := &ehsvc.GetEventsResponse{}
err := eh.GetEventsForUser(context.Background(), &ehsvc.GetEventsForUserRequest{UserID: "test-id"}, resp)
Expect(err).ToNot(HaveOccurred())
Expect(resp).ToNot(BeNil())
// Events don't always come back in the same order as they were sent, so we need to sort them and
// do the same for the expected IDs as well.
expectedIDs := []string{ids[0], ids[2]}
sort.Strings(expectedIDs)
var gotIDs []string
for _, ev := range resp.Events {
gotIDs = append(gotIDs, ev.Id)
}
sort.Strings(gotIDs)
Expect(len(gotIDs)).To(Equal(len(expectedIDs)))
Expect(gotIDs[0]).To(Equal(expectedIDs[0]))
Expect(gotIDs[1]).To(Equal(expectedIDs[1]))
})
It("Stores events and verifies them in the store directly (consumer-only mode)", func() {
id := bus.Publish(events.UploadReady{})
time.Sleep(500 * time.Millisecond)
records, err := sto.Read(id)
Expect(err).ToNot(HaveOccurred())
Expect(len(records)).To(Equal(1))
var stored service.StoreEvent
err = json.Unmarshal(records[0].Value, &stored)
Expect(err).ToNot(HaveOccurred())
Expect(stored.ID).To(Equal(id))
})
})
It("Starts without consumer and reads events from shared store", func() {
// A separate consumer instance stores events into the store shared with the
// consumer-less instance (gRPC-only mode), which can still find them.
bus = testBus(make(chan events.Event))
defer close(bus)
_, err := consumer.NewConsumer(
consumer.Logger(log.Logger{}),
consumer.Config(cfg),
consumer.Persistence(sto),
consumer.Stream(bus),
)
eh, err = service.NewEventHistoryService(cfg, bus, sto, log.Logger{})
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
close(bus)
})
It("Records events, stores them and allows them to be retrieved", func() {
id := bus.Publish(events.UploadReady{})
// service will store eventually
time.Sleep(500 * time.Millisecond)
resp := &ehsvc.GetEventsResponse{}
err = eh.GetEvents(context.Background(), &ehsvc.GetEventsRequest{Ids: []string{id}}, resp)
err := eh.GetEvents(context.Background(), &ehsvc.GetEventsRequest{Ids: []string{id}}, resp)
Expect(err).ToNot(HaveOccurred())
Expect(resp).ToNot(BeNil())
Expect(len(resp.Events)).To(Equal(1))
Expect(resp.Events[0].Id).To(Equal(id))
})
It("Gets all events", func() {
ids := make([]string, 3)
ids[0] = bus.Publish(events.UploadReady{
ExecutingUser: &userv1beta1.User{
Id: &userv1beta1.UserId{
OpaqueId: "test-id",
},
},
Failed: false,
Timestamp: utils.TimeToTS(time.Time{}),
})
ids[1] = bus.Publish(events.UserCreated{
UserID: "another-id",
})
ids[2] = bus.Publish(events.UserDeleted{
Executant: &userv1beta1.UserId{
OpaqueId: "another-id",
},
UserID: "test-id",
})
time.Sleep(500 * time.Millisecond)
resp := &ehsvc.GetEventsResponse{}
err := eh.GetEventsForUser(context.Background(), &ehsvc.GetEventsForUserRequest{UserID: "test-id"}, resp)
Expect(err).ToNot(HaveOccurred())
Expect(resp).ToNot(BeNil())
// Events don't always come back in the same order as they were sent, so we need to sort them and
// do the same for the expected IDs as well.
expectedIDs := []string{ids[0], ids[2]}
sort.Strings(expectedIDs)
var gotIDs []string
for _, ev := range resp.Events {
gotIDs = append(gotIDs, ev.Id)
}
sort.Strings(gotIDs)
Expect(len(gotIDs)).To(Equal(len(expectedIDs)))
Expect(gotIDs[0]).To(Equal(expectedIDs[0]))
Expect(gotIDs[1]).To(Equal(expectedIDs[1]))
})
})
type testBus chan events.Event
+13 -12
View File
@@ -36,18 +36,19 @@ type Config struct {
DisableRadicale bool `yaml:"disable_radicale" env:"FRONTEND_DISABLE_RADICALE" desc:"When set to true, clients are informed that the Radicale (CalDAV/CardDAV) is not accessible." introductionVersion:"4.0.0"`
DefaultLinkPermissions int `yaml:"default_link_permissions" env:"FRONTEND_DEFAULT_LINK_PERMISSIONS" desc:"Defines the default permissions a link is being created with. Possible values are 0 (= internal link, for instance members only) and 1 (= public link with viewer permissions). Defaults to 1." introductionVersion:"1.0.0"`
PublicURL string `yaml:"public_url" env:"OC_URL;FRONTEND_PUBLIC_URL" desc:"The public facing URL of the OpenCloud frontend." introductionVersion:"1.0.0"`
MaxConcurrency int `yaml:"max_concurrency" env:"OC_MAX_CONCURRENCY;FRONTEND_MAX_CONCURRENCY" desc:"Maximum number of concurrent go-routines. Higher values can potentially get work done faster but will also cause more load on the system. Values of 0 or below will be ignored and the default value will be used." introductionVersion:"1.0.0"`
AppHandler AppHandler `yaml:"app_handler"`
Archiver Archiver `yaml:"archiver"`
OCS OCS `yaml:"ocs"`
OCDav OCDav `yaml:"ocdav"`
Checksums Checksums `yaml:"checksums"`
ReadOnlyUserAttributes []string `yaml:"read_only_user_attributes" env:"FRONTEND_READONLY_USER_ATTRIBUTES" desc:"A list of user attributes to indicate as read-only. Supported values: 'user.onPremisesSamAccountName' (username), 'user.displayName', 'user.mail', 'user.passwordProfile' (password), 'user.appRoleAssignments' (role), 'user.memberOf' (groups), 'user.accountEnabled' (login allowed), 'drive.quota' (quota). See the Environment Variable Types description for more details." introductionVersion:"1.0.0"`
LDAPServerWriteEnabled bool `yaml:"ldap_server_write_enabled" env:"OC_LDAP_SERVER_WRITE_ENABLED;FRONTEND_LDAP_SERVER_WRITE_ENABLED" desc:"Allow creating, modifying and deleting LDAP users via the GRAPH API. This can only be set to 'true' when keeping default settings for the LDAP user and group attribute types (the 'OC_LDAP_USER_SCHEMA_* and 'OC_LDAP_GROUP_SCHEMA_* variables)." introductionVersion:"1.0.0"`
EditLoginAllowedDisabled bool `yaml:"edit_login_allowed_disabled" env:"FRONTEND_EDIT_LOGIN_ALLOWED_DISABLED" desc:"Used to set if login is allowed/forbidden for for User." introductionVersion:"3.4.0"`
FullTextSearch bool `yaml:"full_text_search" env:"FRONTEND_FULL_TEXT_SEARCH_ENABLED" desc:"Set to true to signal the web client that full-text search is enabled." introductionVersion:"1.0.0"`
CheckForUpdates bool `yaml:"check_for_updates" env:"FRONTEND_CHECK_FOR_UPDATES" desc:"Enable automatic checking for updates. Defaults to true." introductionVersion:"3.6.0"`
PublicURL string `yaml:"public_url" env:"OC_URL;FRONTEND_PUBLIC_URL" desc:"The public facing URL of the OpenCloud frontend." introductionVersion:"1.0.0"`
MaxConcurrency int `yaml:"max_concurrency" env:"OC_MAX_CONCURRENCY;FRONTEND_MAX_CONCURRENCY" desc:"Maximum number of concurrent go-routines. Higher values can potentially get work done faster but will also cause more load on the system. Values of 0 or below will be ignored and the default value will be used." introductionVersion:"1.0.0"`
AppHandler AppHandler `yaml:"app_handler"`
Archiver Archiver `yaml:"archiver"`
DataGateway DataGateway `yaml:"data_gateway"`
OCS OCS `yaml:"ocs"`
OCDav OCDav `yaml:"ocdav"`
Checksums Checksums `yaml:"checksums"`
ReadOnlyUserAttributes []string `yaml:"read_only_user_attributes" env:"FRONTEND_READONLY_USER_ATTRIBUTES" desc:"A list of user attributes to indicate as read-only. Supported values: 'user.onPremisesSamAccountName' (username), 'user.displayName', 'user.mail', 'user.passwordProfile' (password), 'user.appRoleAssignments' (role), 'user.memberOf' (groups), 'user.accountEnabled' (login allowed), 'drive.quota' (quota). See the Environment Variable Types description for more details." introductionVersion:"1.0.0"`
LDAPServerWriteEnabled bool `yaml:"ldap_server_write_enabled" env:"OC_LDAP_SERVER_WRITE_ENABLED;FRONTEND_LDAP_SERVER_WRITE_ENABLED" desc:"Allow creating, modifying and deleting LDAP users via the GRAPH API. This can only be set to 'true' when keeping default settings for the LDAP user and group attribute types (the 'OC_LDAP_USER_SCHEMA_* and 'OC_LDAP_GROUP_SCHEMA_* variables)." introductionVersion:"1.0.0"`
EditLoginAllowedDisabled bool `yaml:"edit_login_allowed_disabled" env:"FRONTEND_EDIT_LOGIN_ALLOWED_DISABLED" desc:"Used to set if login is allowed/forbidden for for User." introductionVersion:"3.4.0"`
FullTextSearch bool `yaml:"full_text_search" env:"FRONTEND_FULL_TEXT_SEARCH_ENABLED" desc:"Set to true to signal the web client that full-text search is enabled." introductionVersion:"1.0.0"`
CheckForUpdates bool `yaml:"check_for_updates" env:"FRONTEND_CHECK_FOR_UPDATES" desc:"Enable automatic checking for updates. Defaults to true." introductionVersion:"3.6.0"`
Middleware Middleware `yaml:"middleware"`
@@ -101,6 +101,9 @@ func DefaultConfig() *config.Config {
MaxNumFiles: 10000,
MaxSize: 1073741824,
},
DataGateway: config.DataGateway{
Prefix: "data",
},
OCS: config.OCS{
Prefix: "ocs",
SharePrefix: "/Shares",
@@ -153,6 +153,12 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
"max_num_files": cfg.Archiver.MaxNumFiles,
"max_size": cfg.Archiver.MaxSize,
},
"datagateway": map[string]any{
"prefix": cfg.DataGateway.Prefix,
"transfer_shared_secret": cfg.TransferSecret,
"timeout": 86400,
"insecure": true,
},
"ocs": map[string]any{
"storage_registry_svc": cfg.Reva.Address,
"share_prefix": cfg.OCS.SharePrefix,
+2
View File
@@ -24,6 +24,8 @@ type Config struct {
CommitShareToStorageGrant bool `yaml:"commit_share_to_storage_grant" env:"GATEWAY_COMMIT_SHARE_TO_STORAGE_GRANT" desc:"Commit shares to storage grants. This grants access to shared resources for the share receiver directly on the storage." introductionVersion:"1.0.0"`
ShareFolder string `yaml:"share_folder_name" env:"GATEWAY_SHARE_FOLDER_NAME" desc:"Name of the share folder in users' home space." introductionVersion:"1.0.0"`
DisableHomeCreationOnLogin bool `yaml:"disable_home_creation_on_login" env:"GATEWAY_DISABLE_HOME_CREATION_ON_LOGIN" desc:"Disable creation of the home space on login." introductionVersion:"1.0.0"`
TransferSecret string `yaml:"transfer_secret" env:"OC_TRANSFER_SECRET" desc:"The storage transfer secret." introductionVersion:"1.0.0"`
TransferExpires int `yaml:"transfer_expires" env:"GATEWAY_TRANSFER_EXPIRES" desc:"Expiry for the gateway tokens." introductionVersion:"1.0.0"`
Cache Cache `yaml:"cache"`
FrontendPublicURL string `yaml:"frontend_public_url" env:"OC_URL;GATEWAY_FRONTEND_PUBLIC_URL" desc:"The public facing URL of the OpenCloud frontend." introductionVersion:"1.0.0"`
@@ -37,6 +37,7 @@ func DefaultConfig() *config.Config {
CommitShareToStorageGrant: true,
ShareFolder: "Shares",
DisableHomeCreationOnLogin: true,
TransferExpires: 24 * 60 * 60,
Cache: config.Cache{
ProviderCacheStore: "noop",
ProviderCacheNodes: []string{"127.0.0.1:9233"},
@@ -89,6 +90,10 @@ func EnsureDefaults(cfg *config.Config) {
cfg.TokenManager = &config.TokenManager{}
}
if cfg.TransferSecret == "" && cfg.Commons != nil && cfg.Commons.TransferSecret != "" {
cfg.TransferSecret = cfg.Commons.TransferSecret
}
if cfg.GRPC.TLS == nil && cfg.Commons != nil {
cfg.GRPC.TLS = structs.CopyOrZeroValue(cfg.Commons.GRPCServiceTLS)
}
@@ -39,6 +39,10 @@ func Validate(cfg *config.Config) error {
return shared.MissingJWTTokenError(cfg.Service.Name)
}
if cfg.TransferSecret == "" {
return shared.MissingRevaTransferSecretError(cfg.Service.Name)
}
if cfg.StorageRegistry.StorageUsersMountID == "" {
return fmt.Errorf("The storage users mount ID has not been configured for %s. "+
"Make sure your %s config contains the proper values "+
@@ -56,6 +56,9 @@ func GatewayConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]a
"share_folder": cfg.ShareFolder, // ShareFolder is the location where to create shares in the recipient's storage provider.
// other
"disable_home_creation_on_login": cfg.DisableHomeCreationOnLogin,
"datagateway": strings.TrimRight(cfg.FrontendPublicURL, "/") + "/data",
"transfer_shared_secret": cfg.TransferSecret,
"transfer_expires": cfg.TransferExpires,
// cache and TTLs
"provider_cache_config": map[string]any{
"cache_store": cfg.Cache.ProviderCacheStore,
-2
View File
@@ -36,8 +36,6 @@ type Config struct {
Keycloak Keycloak `yaml:"keycloak"`
ServiceAccount ServiceAccount `yaml:"service_account"`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY;GRAPH_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary for the access to resources from other services." introductionVersion:"7.5.0" mask:"password"`
Context context.Context `yaml:"-"`
Metadata Metadata `yaml:"metadata_config"`
@@ -170,10 +170,6 @@ func EnsureDefaults(cfg *config.Config) {
cfg.HTTP.TLS = cfg.Commons.HTTPServiceTLS
}
if cfg.MachineAuthAPIKey == "" && cfg.Commons != nil && cfg.Commons.MachineAuthAPIKey != "" {
cfg.MachineAuthAPIKey = cfg.Commons.MachineAuthAPIKey
}
if cfg.Identity.LDAP.GroupCreateBaseDN == "" {
cfg.Identity.LDAP.GroupCreateBaseDN = cfg.Identity.LDAP.GroupBaseDN
}
-20
View File
@@ -293,26 +293,6 @@ func (i *LDAP) AddMembersToGroup(ctx context.Context, groupID string, memberIDs
if !i.writeEnabled && i.groupCreateBaseDN == i.groupBaseDN {
return errorcode.New(errorcode.NotAllowed, "server is configured read-only")
}
// eliminate duplicates in memberIDs by their UUID, to prevent unnecessary LDAP
// lookups below, and for https://github.com/opencloud-eu/opencloud/issues/3354
{
uniqueMemberIDs := make([]string, 0, len(memberIDs))
memory := map[string]struct{}{}
for _, id := range memberIDs {
if len(strings.TrimSpace(id)) == 0 {
continue // while we're at it, clean the input parameters and skip empty strings
}
if _, present := memory[id]; !present {
uniqueMemberIDs = append(uniqueMemberIDs, id)
memory[id] = struct{}{}
} else {
logger.Debug().Str("id", id).Msg("Duplicate member in group addition. Skipping")
}
}
memberIDs = uniqueMemberIDs
}
ge, err := i.getLDAPGroupByNameOrID(groupID, true)
if err != nil {
return err
@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-11 23:16+0000\n"
"POT-Creation-Date: 2026-07-22 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"
@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-08-11 23:16+0000\n"
"POT-Creation-Date: 2026-07-22 23:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: OpenCloud Ops, 2026\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"
Loaded 100 of 1085 files, more files were not shown because too many files have changed in this diff. Show more