1
0
mirror of https://github.com/owncloud/ocis.git synced 2026-10-23 23:29:02 +03:00
Commit Graph

26 Commits

Author SHA1 Message Date
Prajwol Amatya
29c01920f8 [tests-only][full-ci] test: fix flakiness in e2e-part-2 (#13092)
test: wait for password input field before A11y scan

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>
2026-10-08 14:44:02 +05:45
Asmita Paudel
de0ffcc1e5 [full-ci][tests-only] test : verify public link blocked message after failed password attempts (#13009)
test(e2e): verify public link is blocked after failed password attempts
2026-10-07 11:04:01 +05:45
Matteo
6069640d49 [full-ci] fix(web): break web-pkg/design-system/web-test-helpers dependency cycle (#13038)
fix(web): break web-pkg/design-system/web-test-helpers dependency cycle

web-pkg, design-system and web-test-helpers formed a cycle: the mount
helpers have to install the design system (its components are registered
globally) and web-pkg's mocked pinia stores, so web-test-helpers was
imported by both packages that imported it back.

Resolved by layering the helpers onto the packages that already need
them, instead of adding another one:

  design-system/testing  mount/shallowMount, prop types, design system +
                         gettext + router-link stub plugins
  web-pkg/src/testing    the above, extended with casl abilities, mocked
                         pinia stores and component mocks
  web-test-helpers       re-export of web-pkg/src/testing

design-system sits at the bottom of the workspace graph, so it cannot
depend on a package that installs it - hence the generic half lives
there. web-pkg composes those plugins rather than duplicating them, so
every helper is still defined exactly once, and no package depends on
one above it.

The public API of `@ownclouders/web-test-helpers` is unchanged, so
external extensions are unaffected.

Also:
- pin `typescript` via `pnpm.overrides` - without it, a second peer-
  resolved typescript version forks `vue`, which forks `vue3-gettext`
  into two module instances, breaking `inject(GetTextSymbol)` for any
  component mounted through these helpers.
- keep `@ownclouders/design-system/testing` external in web-pkg's lib
  build. rollup matches `external` strings exactly, so the subpath was
  inlined, shipping a second copy of the design system and of
  @vue/test-utils into the published bundle - components and wrappers
  were then not identity-equal to the consumer's own, and gettext
  injection broke.
- name the web-test-helpers umd output `.cjs`. The package is ESM, so the
  `.js` file that publishConfig.exports pointed `require` at could not be
  required.

Verified: `pnpm install --frozen-lockfile` clean, zero cyclic-workspace
warnings; `pnpm test:unit` 380 files / 3129 tests pass; `pnpm check:types`
0 errors; `pnpm lint`/`check:format` 0 errors; `pnpm build` succeeds;
published artifacts checked by mounting through the built `dist/` bundles
the way an external extension resolves them via publishConfig.exports.
2026-10-02 08:13:31 +02:00
Firas Frikha
3148d79bfa fix: [OCISDEV-1394] explain why an upload does not fit the space quota (#12943) 2026-09-21 15:27:57 +02:00
Asmita Paudel
a700f0cccc [tests-only][full-ci] test: add tests for opening files with # and ? in new tabs (#12865)
test: add tests for opening files with # and ? in new tabs
2026-09-18 16:59:45 +05:45
David Walter
4712c7c619 feat(web): add mermaid-editor app for standalone .mmd diagrams (#12676)
* feat(web): add mermaid-editor app for standalone .mmd diagrams

md-editor-v3's mermaid support only fires inside a Markdown fenced
code block, so there was no way to edit a Mermaid diagram on its own.
This adds a dedicated split-pane editor/preview app (mirroring
web-app-html-editor's shape) for the mmd/mermaid extensions, feeding
raw diagram source straight into mermaid.render() - no Markdown
wrapping involved. Invalid syntax surfaces an inline error instead of
crashing the preview pane, and the rendered SVG is sanitized with
DOMPurify the same way the embedded markdown-mermaid renderer already
does.

๐Ÿค– Generated with Claude Code
Signed-off-by: David Walter <david.walter@kiteworks.com>

* test(web): add e2e coverage and WCAG 2.2 checks for mermaid-editor

Wires the new 'mmdFile' resource type into the create/edit e2e
resource helpers (mirroring txtFile/mdFile) and adds a spec covering
diagram rendering, invalid-syntax error surfacing, and the view-mode
toggle. The new mermaidEditor.ts page-object asserts the existing
WCAG 2.1 a11y baseline every other e2e spec uses, plus an additional
WCAG 2.2 tag scan (target-size, focus-appearance, etc.) scoped to
this file only - the shared a11y helper used by every other spec
stays on its current WCAG 2.1 tag set, since widening it repo-wide is
a separate decision with its own pre-existing-violation triage cost.

๐Ÿค– Generated with Claude Code
Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(web): register mermaid-editor in the default enabled apps list

CI's e2e run for the new mermaid-editor app timed out waiting for the
"New > Mermaid diagram" menu entry: config.json.dist (a reference/dev
file) had "mermaid-editor" added, but the actual runtime default config
a packaged oCIS binary serves comes from services/web's Go defaults,
which didn't. Also runs Prettier over the 3 files check:format flagged.

๐Ÿค– Generated with Claude Code
Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(web): correct vue3-gettext version, add changelog entry

vue3-gettext was pinned to an exact "2.4.0" in web-app-mermaid-editor's
package.json (a copy-paste slip) instead of "^4.0.1" like every other
web app package, pulling in a stray v2 dependency tree with its own
deprecated transitives (glob@7.2.3, inflight@1.0.6). Also adds the
changelog/unreleased entry this PR was missing.

๐Ÿค– Generated with Claude Code
Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(web): resolve stale mermaid lockfile entry from merge conflict

web/pnpm-lock.yaml pinned mermaid to 11.16.0 for the new
web-app-mermaid-editor importer, left over from a badly-resolved merge
with master (which resolves mermaid to 11.16.1 in every other
importer and in the packages snapshot). pnpm install --frozen-lockfile
failed in CI with ERR_PNPM_LOCKFILE_MISSING_DEPENDENCY since 11.16.0
had no corresponding packages entry.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: dj4oC <david.walter@kiteworks.com>

* test(web): register mermaid-editor in the e2e CI oCIS config

tests/config/ci/ocis-config.json is the WEB_UI_CONFIG_FILE the e2e
docker-compose stack (tests/acceptance/docker/src/ocis-base.yml) feeds
the oCIS instance under test. It keeps its own "apps" allowlist,
separate from services/web's Go defaults (already fixed) and
config.json.dist (also already fixed) - and it never got
"mermaid-editor" added. Without it, the running instance never
registers the app, so the "New > Mermaid diagram" menu entry the
mermaidEditor.spec.ts e2e test waits for never renders, and the click
times out after all retries.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: dj4oC <david.walter@kiteworks.com>

* fix(web): give the mermaid-editor CodeMirror pane an accessible name

The plain-text CodeMirror content div renders with role="textbox"
aria-multiline="true" but no aria-label/aria-labelledby/title, which
axe-core (and screen readers) flag as a serious WCAG violation - this
is exactly what the e2e a11y scan caught on the new mermaidEditor
spec. Fixed via EditorView.contentAttributes, the same mechanism
CodeMirror exposes for this. MermaidEditorPane.spec.ts is updated to
install defaultPlugins() like its sibling specs already do, since the
component now calls useGettext() for the label text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: dj4oC <david.walter@kiteworks.com>

---------

Signed-off-by: David Walter <david.walter@kiteworks.com>
Signed-off-by: dj4oC <david.walter@kiteworks.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 22:00:47 +02:00
Gaurav Soni
b99e8ff0a7 feat: [OCISDEV-137] inline markdown editor images as base64 (#12967)
* feat: [OCISDEV-137] inline markdown editor images as base64
2026-09-17 10:47:58 +02:00
Prajwol Amatya
ea160dc90f [tests-only][full-ci]test: fix flaky app provider test (#12953)
* test: rearrange login step

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>

* test: reclick until the dropdown is visible

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>

* test: delete the content before pasting new content

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>

* test: redo fill and waiting if fail

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>

---------

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>
2026-09-15 12:50:35 +05:45
Matteo
73b26532fe [full-ci] chore: [OCISDEV-215] replace axios with the native fetch API in Web (#12910)
* feat(web-client): add native fetch http core

* test(web-test-helpers): replace axios mocks with fetch-shaped helpers

* refactor(web-pkg): build HttpClient on the fetch core

* refactor(web-pkg): unify ClientService interceptors on the fetch core

* refactor(web-pkg): drop axios types from useRequest

* fix(web): align error and header access with the fetch core

* refactor(web-client): move ocs onto the fetch core

* refactor(web-client): move webdav helpers onto the fetch core

* chore(web-client): regenerate graph client with typescript-fetch

* refactor(web-client): adapt graph wrappers to the fetch-based generated client

Regenerate the libre-graph client with the typescript-fetch template and
rewrite the eight facade factories against it:

- the generated APIs are classes (`new XxxApi(config)`), take a single
  request-parameters object and resolve to the payload rather than an
  envelope, so the wrappers no longer destructure `{ data }`
- every generated request is routed through `FetchClient` via
  `Configuration.fetchApi`, keeping header injection, maintenance
  detection and `HttpError`-on-non-2xx intact. Callers keep seeing
  `HttpError` with `statusCode` and `data`, never `ResponseError`
- `toInitOverrides` merges our per-request headers into the generated
  `RequestInit` instead of replacing them, which a plain object would do
  because the runtime spreads `initOverrides` shallowly
- undeclared query parameters travel on a symbol-keyed channel, since the
  runtime assembles the URL before it applies `initOverrides`

`--type-mappings=DateTime=string` keeps date-times as strings, matching
what the previous template emitted and what the app expects.

* refactor: use the generated property names for OData-annotated graph fields

The typescript-fetch template emits real JSON serializers, so annotated
fields like `@libre.graph.permissions.actions`, `@odata.id`, `@UI.Hidden`
and `@client.synchronize` are mapped to camelCase properties on the way in
and back to their wire names on the way out. The wire format is unchanged;
only the TypeScript-side names are. Reads left on the old names would have
silently resolved to `undefined`, and writes would have been dropped.

The OData `$filter` expression in FileSideBar keeps its annotated spelling,
being a query value rather than a property.

Response-only fields are now `readonly`, which the editable copies and test
fixtures built from them need to opt out of, hence `writeable()`.

* chore: drop the axios dependency

Nothing imports axios any more, so remove it from the eight manifests that
declared it and update the web-client README, whose usage examples still
instantiated an axios client.

Also applies prettier to the files touched over the course of the migration.

* fix(web-pkg): keep the axios-era surface on HttpClient

Dropping axios changed more than the transport. Four spellings that consumers
outside this repo were written against disappeared with it, and none of them had
to.

Response headers were a plain lowercased object under axios, so `headers['etag']`
was the only way to read one; a fetch `Response` exposes a `Headers`, where
`get('etag')` is. `httpHeaders` wraps the native object in a proxy that answers
both, case-insensitively, and enumerates the lowercased names โ€” it stays a real
`Headers`, so neither spelling is a migration.

A rejected request carried its body on `error.response.data` and its status on
`error.response.status`. `HttpError` names them `data` and `statusCode`, which
this repo unifies on, but the response those shadow is reachable from outside it,
so `buildError` defines both on the response as well and keeps axios's
`Request failed with status code <n>` message. The body is read from a clone, so
callers still get an unread one.

The config `HttpClient` takes has always named the request body `data`, and web
extensions pass `data` when they issue raw WebDAV requests through
`httpAuthenticated`. Carrying the core's `body` up would have dropped those
bodies silently, so `RequestConfig` keeps `data` and `send` translates it. For
the same reason a default-responseType body that is not JSON falls back to the
raw text instead of throwing: a WebDAV multistatus answered without an explicit
`responseType: 'text'` used to arrive as a string, and a `SyntaxError` there
would turn a working request into a failing one.

`cancel()` is back, on an `AbortController` instead of a `CancelToken`. Combining
the client-wide signal with a per-request one needs a listener per request, so
`send` disposes of them once the request has settled rather than letting them
accumulate on a long-lived client.

`mockAxiosResolve` and `mockAxiosReject` stay exported from web-test-helpers as
deprecated aliases, so suites written against the axios era keep compiling.

* fix(web-client): keep read-only graph fields in request bodies

The typescript-fetch templates omit fields the spec marks `readOnly: true` from
the generated `*ToJSON` serializers. Every field of `Quota` is annotated that
way, so `updateDrive(id, { quota: { total: 500 } })` went out as
`{ quota: {} }` and quotas could no longer be changed. Seventeen other models
were affected the same way, among them `UserUpdate` and `ItemReference`.

The annotation is now stripped from the spec before generating, which is what
the axios-generated client effectively did. That also drops the `readonly`
modifiers, so the `writeable` escape hatch is no longer needed.

* fix(web-client): let graph errors keep their status and body

The generated runtime wraps whatever its `fetchApi` throws in a `FetchError`,
which buried the `HttpError` the core raises for a non-2xx response. Callers
that branch on the status saw neither `statusCode` nor `data`, so the banned
password hint on a public link never appeared and an aborted graph request
stopped looking like an abort.

Rethrowing from an `onError` middleware escapes the wrap for every graph
operation at once.

* fix(web-client): let fetch set the multipart boundary for FormData bodies

A caller-supplied `Content-Type: multipart/form-data` carries no boundary. Axios
replaced the header before sending, fetch passes it through, so the server could not
parse the body and the admin settings logo upload silently did nothing.

* fix(web): merge request headers case-insensitively, plus PR review fixes

Header names are case-insensitive, but the header layers were merged with an
object spread, where object keys are not. `Authorization` and `authorization`
both survived it, and a spec-compliant `Headers` applies a record init with
`append`, so the two were joined into `Bearer stale, Bearer fresh` instead of
the override replacing the token. The graph bridge lowercased every per-request
header name while the client-wide ones are canonically cased, which made the
collision the normal case rather than an edge one.

Merge each layer with `Headers.set()` instead, in the fetch client and in the
graph `initOverrides` bridge, which had its own copy of the same spread. The
new specs run under `@vitest-environment node`: happy-dom's `Headers` applies a
record init with `set` semantics and would hide the bug.

Also from the PR review:

- read an error body with the caller's `responseType` rather than cloning the
  response, so a `blob` caller keeps getting a Blob on `error.data`
- treat any rejection on an aborted signal as an abort, since `abort(reason)`
  rejects with the reason verbatim and only defaults to an `AbortError`
- share the maintenance-mode `onResponse` handler between the webdav client and
  `ClientService`, with their pre-existing disagreement about clearing on an
  unrelated error made explicit instead of silently unified
- pass the graph headers straight through as a `HeadersInit` and drop the
  unused `httpClient` from the graph factory options
- collapse `combineSignals` onto `AbortSignal.any`
- let an abort through `getFileContents` unwrapped
- assert maintenance detection against the real `shouldResponseTriggerMaintenance`
  instead of a mock, which had been hiding that a 500 is not a maintenance signal

* chore(web): drop leaked test title prefixes, document the maintenance-mode widening

* fix(web): keep graph fields the generated decoder used to lose

The typescript-fetch templates rebuild every response from the fields the
spec declares, which is what lets them rename the OData annotated fields.
Two consequences were unhandled.

A field the spec does not declare is dropped. oCIS returns `attributes` on
users, filled from OCIS_USER_SEARCH_DISPLAYED_ATTRIBUTES and displayed by the
sharing autocomplete, and the field is not part of the upstream spec. It is
now declared before generating, and the generation script fails if the spec
stops matching the line it patches, so the field cannot go missing silently.

A declared field the server omits is present holding `undefined`, so
`'accountEnabled' in user` no longer says whether the server sent it. Three
places read it that way: the login select in the user edit panel showed no
value at all, its watcher kept reporting unsaved changes, and sorting the user
list by login threw on `undefined.toString()`. The same went for
`'total' in quota`, which showed a personal quota of `?` for users without one.
2026-09-15 06:23:31 +02:00
Michal Klos
e76a9668e9 fix: [ocisdev-1207] user and light-user e2e tests (#12928) 2026-09-14 10:13:49 +02:00
isha
237f593ee0 [test-only][full-ci] Test: fix flaky e2e-app-provider (#12934)
ci: fix flaky e2e-app-provider
2026-09-11 17:26:36 +05:45
isha
f2a4430937 [test-only] ci: fix flaky e2e-app-provider (#12880)
* ci: fix flaky e2e-app-provider

* ci: fix flaky e2e-app-provider
2026-09-11 11:34:35 +05:45
Michal Klos
768f7d4fa0 fix: [OCISDEV-1207] enforce permissions on vault routes (#12884)
* fix: [OCISDEV-1207] enforce permissions on vault routes

* fix: [OCISDEV-1207] enforce permissions on vault routes

* fix: [OCISDEV-1207] enforce permissions on vault routes

* fix: [OCISDEV-1207] enforce permissions on vault routes, adapt test role

* fix: [OCISDEV-1207] enforce permissions on vault routes, adapt test

* fix: [OCISDEV-1207] enforce permissions on vault routes, adapt test
2026-09-09 12:44:45 +02:00
Kavita gautam
9dcd26a53a [tests-only] test: Cleanup OTP Credentials after MFA (#12853)
* test: cleanup otp credentials after mfa

* test: cleanup using globalBeforeHook and globalCleanup custom hooks

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

---------

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>
2026-09-03 09:52:49 +05:45
David Walter
4d9c46f3a7 feat(collaboration): close WOPI property gaps (#12593)
* feat(collaboration): add Version to Collabora WOPI CheckFileInfo

Add Version field to the Collabora struct to match Microsoft and OnlyOffice
implementations. This allows Collabora Online to properly detect stale
documents for cache invalidation and document reload detection, which is
particularly important in multi-node Kubernetes deployments.

- Add Version field to Collabora struct with json:"Version,omitempty" tag
- Add case for KeyVersion in Collabora.SetProperties method
- Update existing Collabora integration tests to verify Version is populated
- Add three unit tests for Version handling in collabora_test.go
- Add integration test verifying Collabora CheckFileInfo response includes Version

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add LastModifiedTime to Collabora CheckFileInfo for conflict detection

Add LastModifiedTime to the Collabora struct to match Microsoft and OnlyOffice,
and implement the X-COOL-WOPI-Timestamp conflict detection PutFile relies on to
use it. Collabora Online tracks the LastModifiedTime it received in
CheckFileInfo and sends it back during PutFile; without this field the WOPI
host has no way to detect that a file changed since Collabora last checked it,
so concurrent edits could silently overwrite each other.

- Add LastModifiedTime field to Collabora struct (json:"LastModifiedTime,omitempty")
  and wire it in Collabora.SetProperties via the existing KeyLastModifiedTime constant
- fileconnector.go already populates KeyLastModifiedTime unconditionally for all
  targets, so no gating changes were needed there
- Add HeaderCoolWopiTimestamp ("X-COOL-WOPI-Timestamp") constant and thread it
  from HttpAdapter.PutFile through the ContentConnectorService.PutFile interface
- ContentConnector.PutFile compares the client-supplied timestamp against the
  file's current mtime and returns a new NewResponseCOOLConflict() (409,
  COOLStatusCode 1010) on mismatch; an empty timestamp (Microsoft/OnlyOffice,
  and file-creation call sites in PutRelativeFileSuggested/Relative) skips the
  check entirely, so existing WOPI clients see no behavior change
- Hand-updated the mockery-generated ContentConnectorService mock (mockery
  itself fails to build under the local Go toolchain) and every PutFile call
  site/mock expectation across fileconnector.go, fileconnector_test.go,
  contentconnector_test.go and httpadapter_test.go for the new 5-arg signature
- Add fileinfo/collabora_test.go unit tests for LastModifiedTime SetProperties/
  JSON marshalling/omitempty, update the 3 existing Collabora CheckFileInfo
  integration tests with the expected LastModifiedTime, and add PutFile tests
  covering COOL timestamp mismatch (409) and match (success) in
  contentconnector_test.go

๐Ÿค– Generated with Claude Code

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(collaboration): handle nil Mtime and add HttpAdapter test coverage for COOL WOPI timestamp

The COOL conflict-detection check in ContentConnector.PutFile treated a
nil Mtime as an automatic mismatch, causing a permanent 409 on every
save for files with no recorded mtime. Skip the comparison (fail open)
when Mtime is nil, matching CheckFileInfo's fallback posture. Also add
a regression test for that case, plus a test asserting HttpAdapter.PutFile
correctly reads the X-COOL-WOPI-Timestamp header and passes it through
to the content connector, which previously had no coverage.

Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add ReadOnly to Collabora WOPI CheckFileInfo

Add ReadOnly to the Collabora struct to match Microsoft and OnlyOffice, and
populate it in CheckFileInfo for all three targets. KeyReadOnly already
existed as a constant and both Microsoft.SetProperties and
OnlyOffice.SetProperties already had a `case KeyReadOnly:`, but nothing in
fileconnector.go ever put a value into the properties map for it - so
ReadOnly was silently false for every WOPI target, regardless of whether the
user actually had write access.

- Add ReadOnly field to the Collabora struct (json:"ReadOnly", no omitempty,
  consistent with Microsoft/OnlyOffice since false is meaningful) and wire it
  in Collabora.SetProperties via the existing KeyReadOnly constant
- In fileconnector.go's CheckFileInfo, set
  infoMap[fileinfo.KeyReadOnly] = wopiContext.ViewMode != VIEW_MODE_READ_WRITE
  unconditionally for all targets. wopiContext.ViewMode is already resolved
  upstream from the actual CS3 permissions, space status and lock state, so
  this derives ReadOnly from that single source of truth instead of
  re-deriving the same signals in the connector
- Add fileinfo/collabora_test.go unit tests for ReadOnly SetProperties (true/
  false) and JSON marshalling (asserting the field is present for both true
  and false, since there is no omitempty)
- Add two new CheckFileInfo integration tests asserting ReadOnly=true for a
  view-only mode and ReadOnly=false for read-write, and add ReadOnly: true to
  the 4 existing CheckFileInfo integration tests that assert a full
  Microsoft/Collabora/OnlyOffice struct under a non-read-write ViewMode
  (the 2 ViewMode assignments in the Lock/GetLock test block were left
  untouched since those tests don't assert against a FileInfo struct)

๐Ÿค– Generated with Claude Code

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add SupportsUpdate to Collabora WOPI CheckFileInfo

Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(collaboration): add missing godoc comment to Collabora.SupportsUpdate

Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add IsAnonymousUser to Collabora WOPI CheckFileInfo

Implement support for the IsAnonymousUser property in the Collabora struct,
enabling Collabora Online to distinguish between authenticated and anonymous
users (public share access). This property is derived from the user context's
public-share-role indicator and is already computed in fileconnector.go.

Changes:
- Add IsAnonymousUser field to Collabora struct with omitempty tag
- Wire KeyIsAnonymousUser case in SetProperties
- Add unit tests: SetProperties behavior, JSON omit/include when false/true
- Add integration tests: anonymous user context returns true, authenticated
  user returns false, UserId still populated for anonymous users

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add URL properties to Collabora WOPI CheckFileInfo

Add the 7 MS-WOPI file URL properties (CloseUrl, DownloadUrl,
FileSharingUrl, FileVersionUrl, HostEditUrl, HostViewUrl, SignoutUrl)
to the Collabora fileinfo struct, mirroring the Microsoft struct's
existing fields and JSON tags. This is struct/SetProperties wiring
only; fileconnector.go population follows in a subsequent commit.

SignoutUrl is intentionally left unpopulated in CheckFileInfo (no
fileconnector.go change): the collaboration service has no OIDC
issuer/logout configuration to build a real sign-out URL from, so
Collabora reaches parity with Microsoft/OnlyOffice's existing
"field exists but is never populated" gap rather than introducing a
new one.

Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): populate CloseURL and DownloadURL in CheckFileInfo

CloseURL and DownloadURL were never populated in CheckFileInfo for any
WOPI target (Microsoft, OnlyOffice, or Collabora), despite Microsoft's
struct having had these fields all along.

- CloseURL reuses the existing parentFolderURL (the same "folder
  containing the file" URL already used for BreadcrumbFolderURL)
  rather than building a second URL for the same concept. This flows
  through the shared infoMap, so it now also reaches Microsoft and
  OnlyOffice, both of which already declare KeyCloseURL in their
  SetProperties switch; existing full-struct-equality test
  expectations are updated accordingly.

- DownloadURL is built by a new createFileDownloadURL helper pointing
  at this service's own GET /wopi/files/{fileid}/contents route,
  authenticated with a freshly generated WOPI access token. It shares
  its "generate token + build hashed-resource-id path + attach
  access_token query param" logic with the existing template
  createDownloadURL via an extracted createWopiResourceURL helper,
  rather than duplicating it. Population is defensive: if WOPI token
  generation fails, DownloadURL is simply omitted (logged) instead of
  failing the whole CheckFileInfo request, mirroring the existing
  TemplateSource pattern.

HostViewURL, HostEditURL, FileSharingURL, and FileVersionURL needed no
fileconnector.go change - they were already unconditionally computed
into infoMap; only Collabora's struct lacked the fields to receive
them (added in the previous commit).

Adds integration test coverage for: CloseURL/BreadcrumbFolderURL
reuse, HostEditURL vs HostViewURL distinctness, the DownloadURL route
pattern, and graceful omission of DownloadURL when WOPI token
generation fails (via ShortTokens with no store configured) without
the overall request failing.

Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): complete Breadcrumb properties in Collabora WOPI CheckFileInfo

Add the four Breadcrumb* fields to the Collabora fileinfo struct that were
already present on Microsoft/OnlyOffice (BreadcrumbFolderName/URL just
needed struct wiring; BreadcrumbBrandName/URL needed new logic in
CheckFileInfo, derived from the CS3 StorageSpace Name/Root).

BreadcrumbBrandURL is withheld for public-share (anonymous) access, mirroring
the existing precedent for parentFolderURL/CloseURL, since it would expose
an internal space/resource id an anonymous user has no other way to reach.
BreadcrumbBrandName is just a display string and stays populated either way.

Also guards the new brand URL construction against a nil space root so it
degrades to an empty string instead of a misleading bare ".../f" URL when
no space info is available.

๐Ÿค– Generated with Claude Code

Signed-off-by: David Walter <david.walter@kiteworks.com>

* test(collaboration): cover BreadcrumbBrandURL when space has no root

Add a new test case to verify that when a StorageSpace has a Name but
a nil Root, the BreadcrumbBrandName is populated while BreadcrumbBrandURL
remains empty, ensuring the nil-guard doesn't allow malformed URLs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add PostMessage properties to Collabora WOPI CheckFileInfo

Add ClosePostMessage, EditModePostMessage, EditNotificationPostMessage,
FileSharingPostMessage, and FileVersionPostMessage to the Collabora
fileinfo struct with SetProperties wiring and godoc comments, mirroring
what OnlyOffice already exposes.

Only EditModePostMessage is actually populated in CheckFileInfo, gated
to the Collabora target: the oCIS web frontend's iframe wrapper
(web-app-external/src/App.vue, shared by all WOPI targets) only has a
real postMessage handler for UI_Edit today. The other four flags are
left unset so Collabora falls back to the corresponding URL properties
(HostEditURL/HostViewURL/FileSharingURL/FileVersionURL, added in an
earlier task) instead of firing PostMessages nobody listens for.

Because OnlyOffice's SetProperties already implements these same keys,
the Collabora-only behavior requires an explicit `if` gate on
f.cfg.App.Product rather than an unconditional map write, to avoid
silently changing OnlyOffice's current (all-absent) behavior.

Signed-off-by: David Walter <david.walter@kiteworks.com>

* feat(collaboration): add Collabora-specific IsUserLocked and IsAdminUser to WOPI CheckFileInfo

Add the two Collabora-only WOPI CheckFileInfo properties: IsUserLocked
(applies coolwsd.xml locked_commands to the user) and IsAdminUser
(unlocks Collabora's server audit panel).

- IsUserLocked is derived from the existing "secure view" condition
  already used to gate DisableExport/DisableCopy/DisablePrint/
  WatermarkText (ViewMode == VIEW_MODE_VIEW_ONLY with a non-empty
  ViewOnlyToken), applied regardless of public-share vs authenticated
  user.
- IsAdminUser is derived from the CS3 user's Opaque.Map["roles"] JSON
  array (the same raw data ocis-pkg/middleware/account.go lifts into
  go-micro metadata), compared against
  defaults.BundleUUIDRoleAdmin only - SpaceAdmin and other roles do
  not qualify.

Both keys have no matching SetProperties case in Microsoft/OnlyOffice,
so they are silently dropped for those targets, consistent with the
existing pattern for other Collabora-only properties in this
connector. No new config surface was added, matching the scoping
approach used throughout this properties-gap series.

๐Ÿค– Generated with Claude Code

Signed-off-by: David Walter <david.walter@kiteworks.com>

* test(collaboration): remove redundant Collabora omitempty test duplicates

TestCollaboraVersionOmitEmpty and TestCollaboraLastModifiedTimeOmitEmpty
fully duplicated the coverage already provided by
TestCollaboraJSONMarshallingIncludesVersion and
TestCollaboraJSONMarshallingIncludesLastModifiedTime (both already assert
JSON inclusion/omission via a shouldInclude flag). Removing the duplicates
also drops an unused `expected` table field flagged by the final
whole-branch review.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* docs(changelog): add changelog entry for Collabora WOPI CheckFileInfo gaps

Signed-off-by: David Walter <david.walter@kiteworks.com>

* test(collaboration): fix checkFileInfo acceptance tests for ReadOnly derivation

Four "check file info with different mode(s)" scenario outlines
(onlyOffice/fakeOffice, personal space and project space) hardcoded
"ReadOnly": {"const": false} for every view mode. That was accurate only
because ReadOnly was never actually populated in CheckFileInfo before this
PR (it silently defaulted to Go's zero value). Now that ReadOnly correctly
reflects whether the WOPI session grants write access
(ReadOnly = ViewMode != READ_WRITE, the exact negation of UserCanWrite),
"view" and "read" mode responses correctly report ReadOnly: true, which
these tests now assert via a new "read-only" Examples column instead of a
static const.

The "check file info with different view-mode (collabora)" scenario is
unaffected: it never asserted ReadOnly in its schema.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* revert(collaboration): remove X-COOL-WOPI-Timestamp PutFile conflict detection

CI on owncloud/ocis PR #12593 reproducibly failed the e2e test
web/tests/e2e/specs/app-provider/officeSuites.spec.ts:17:3 "create an
OpenDocument file with Collabora" across two independent full CI runs,
timing out after 180s behind a Collabora "document conflict" popup that
intercepts all clicks.

Server logs showed the new PutFile conflict check firing on literally
the first save of a freshly-created document, with a consistent ~8s gap
between the client's cached X-COOL-WOPI-Timestamp and the server's
current mtime that never resolved across 6+ retries over 3+ minutes.
This is most likely oCIS's async post-processing (search indexing,
thumbnailing, etc.) legitimately bumping the file's mtime shortly after
creation - something this comparison can't distinguish from a real
edit conflict, and which Collabora's client doesn't recover from
automatically.

Revert just the conflict-detection portion of task 02: the
coolWopiTimestamp parameter on ContentConnectorService.PutFile / its
implementation, the X-COOL-WOPI-Timestamp header handling in
HttpAdapter.PutFile, and NewResponseCOOLConflict, plus their tests and
mock signatures. The LastModifiedTime WOPI property (and everything
else task 02 added) is untouched and remains fully intact.

๐Ÿค– Generated with Claude Code

Signed-off-by: David Walter <david.walter@kiteworks.com>

* test(web): add e2e Playwright coverage for WOPI CheckFileInfo properties

Adds dedicated Playwright specs, each covering both Collabora and
OnlyOffice, for the WOPI CheckFileInfo properties this PR added that
have a genuinely observable, already-proven-safe browser-level signal:

- wopiReadOnly.spec.ts: false for the file owner, true for a
  view-only share recipient (via the existing canEditCollaboraDocument/
  canEditOnlyOfficeDocument-backed userShouldNotBeAbleToEditContentOfResources
  step).
- wopiSupportsUpdate.spec.ts: a new document created via the office
  suite's own "New" menu (PutRelativeFile) persists its content across
  a reopen.
- wopiVersionAndLastModifiedTime.spec.ts: an edit saved by one actor is
  visible to a second actor opening the file afterward, rather than a
  stale cached copy.
- wopiCloseUrl.spec.ts: closing the editor navigates the top-level page
  back into the files app.

All four are built exclusively from step-level helpers already proven
reliable elsewhere in this suite (officeSuites.spec.ts, secureView.spec.ts)
- no new selectors into Collabora's or OnlyOffice's own iframe DOM.

Not added: dedicated e2e tests for BreadcrumbBrandName/Url,
EditModePostMessage, IsUserLocked, and IsAdminUser. CheckFileInfo is a
server-to-server call the office suite's own backend makes directly to
the collaboration service - it is never visible to the browser, so
Playwright cannot observe the JSON response for any property. These
four also have no independently observable browser effect without
either inventing unverified selectors into third-party iframe internals
(breadcrumb bar, edit-mode button) or Collabora-side configuration
(locked_commands, audit panel) this test environment doesn't set up.
They remain correctly covered by the Go unit/integration tests
(fileinfo/collabora_test.go, fileconnector_test.go) and the
tests/acceptance/features/apiCollaboration/checkFileInfo.feature
acceptance suite, which assert the actual JSON response server-side.

An initial IsAnonymousUser spec was written and dropped after review:
it only asserted that content loads, which IsAnonymousUser does not
gate, making it indistinguishable from a regression (already covered
correctly at the Go level in fileconnector_test.go).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(web): reformat wopiVersionAndLastModifiedTime.spec.ts for prettier

pnpm check:format (web-build-test CI job) flagged the test.describe()
call: its 3 arguments (title, options, callback) didn't fit within
this repo's printWidth 100 on one line, so prettier expects them
wrapped one per line. Reformatted to match and reindented the
describe block body accordingly. No logic change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

* fix(collaboration): address PR #12593 review findings

- Restructure the VIEW_ONLY watermark check to nest inside the
  ViewOnlyToken check instead of repeating the condition, per
  jvillafanez's review comment.
- Add a reva token mint/dismantle round-trip test covering the admin
  role Opaque entry, exercising the real JWT serialization seam
  IsAdminUser depends on rather than only direct context injection,
  per DeepDiver1975's review.
- Correct the changelog entry: ReadOnly/CloseUrl (and DownloadUrl for
  Microsoft) already had matching `case` handling in microsoft.go/
  onlyoffice.go, so populating them unconditionally changes those
  targets' output too, not just Collabora's. Only IsUserLocked/
  IsAdminUser are genuinely Collabora-only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>

---------

Signed-off-by: David Walter <david.walter@kiteworks.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Juan Pablo Villafaรฑez <jpvillafanez@izertis.com>
2026-08-25 18:01:56 +02:00
Sujeito Operator
0e63a8d034 [tests-only][full-ci] test: fix flaky login error assertion in userFailsToLogin (#12843)
test: fix flaky login error assertion in userFailsToLogin

config.timeout is declared in seconds and every other Playwright call site
multiplies it by 1000. session.ts passed it through unconverted, so the
assertion had 180ms rather than 180s to observe a message that only renders
after the sign-in round-trip completes.

The assertion was also not awaited. expect() here is @playwright/test's, so
toBeVisible() returns a Promise; unawaited, the a11y audit on the next line
ran before it settled.
2026-08-25 10:02:10 +05:45
Pradip Subedi
d84bab1a3e [tests-only][full-ci] test: fix flaky spaces e2e tests (#12809)
* test: fix flaky spaces e2e by reducing a11y scan overhead and labeling the space image spinner

* test: remove changes in actions.ts
2026-08-24 16:47:18 +05:45
Kavita gautam
c828e41cba chore: Add Vault Mode CI setup for E2E tests (#12577)
* feat: vault mode access control and mfa on vault entry

* chore: vault mode ci setup for e2e tests

chore: vault mode ci setup

* test: restore web packages changes

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: remove keycloak certs

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: set keycloak server envs

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: adding csp file

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: adding keycloak config

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: adding scope with email acr

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: exclude vault storage from parallel e2e tests

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: remove debugging codes

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: handle vault mode in keycloak group setup

* test: revert some configs

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* test: updating the vault pageObject layout

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* fix: reusing otp authentication of mfa

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>

* fix: update userAuthenticatesWithOTP function

* fix: use a new OIDC authorization-code login for OCIS token

---------

Signed-off-by: Kavita Gautam <kavita@jankaritech.com>
2026-08-20 16:26:01 +05:45
Matteo
b97840e770 fix: [OCISDEV-1358] shift-click range selection in the files list (#12804)
* fix: [OCISDEV-1358] shift-click range selection in the files list

Shift-clicking a checkbox now triggers range selection, a plain
shift-click replaces the current selection instead of adding to it, and
the browser no longer highlights the text of the affected rows.

* fix: [OCISDEV-1358] keep the checkbox checked state in sync with the model

The browser toggles the native checked property on every click, while vue does
not re-patch an unchanged model-value, so the property stayed flipped whenever a
click did not change the selection, e.g. when a range selection keeps an already
selected resource selected. The tiles view worked around that by preventing the
default click action, which desyncs the property for good: chromium restores the
pre-click value after vue has already patched it, so it never follows the model
again.

Sync the native property from the model in OcCheckbox once the parent had its
chance to react to the change, and drop the workaround.
2026-08-18 13:04:08 +02:00
Prajwol Amatya
c53e2f773e [tests-only][full-ci] test: fix flaky e2e test for tag search (#12780)
test: login user after creating resources via API

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>
2026-08-13 11:13:38 +05:45
Prajwol Amatya
f6628b6264 [tests-only][full-ci] test: fix flaky e2e test in e2e-part-3 (#12778)
* test: slow down test run

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>

* test: scope temp upload path per Playwright worker

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>

---------

Signed-off-by: Prajwol Amatya <prajwolamatya11@gmail.com>
2026-08-12 12:30:12 +05:45
Michal Klos
90148451c8 chore: bump go and web packages (#12765)
* chore: bump go packages

* chore: bump web packages
2026-08-10 11:43:14 +02:00
isha
2f70a6856f build(deps): Bump dependencies (#12620)
* build(deps): bump pnpm dependencies

* style(web): format code with prettier

Signed-off-by: Lukas Hirt <info@hirt.cz>

* test(web): update ActivitiesPanel snapshot for dompurify/happy-dom sanitization change

The dependency bump upgraded dompurify to 3.4.3+, which combined with
happy-dom's DOM implementation drops a leading <strong> tag that is the
first sanitized child node. Real browsers are unaffected; only the
happy-dom test snapshot needed updating.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-authored-by: Lukas Hirt <info@hirt.cz>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 16:20:30 +02:00
Matteo
5e7ce5c7de fix: resolve e2e violations in web UI (#12597)
- OcBreadcrumb: add `inert` to truncation placeholder <li> so its
  focusable <a> child is unreachable (fixes aria-hidden-focus)
- OcTable: remove aria-hidden from header cell span and fall back to
  field.name so icon/avatar columns always have discernible text
  (fixes empty-table-header)
- Plain layout: wrap router-view in <main> so login/public-link pages
  have a landmark (fixes region violations)
- SidebarNav: change root element to <aside> with aria-label so the
  versions div is inside a landmark (fixes region violations)
- web-app-ocm App: change root element to <main> (fixes region)
- Add v-if="pageTitle" to sr-only <h1> in 6 components so empty
  headings are never rendered (fixes empty-heading)
- Disable aria-allowed-role in search dropdown check โ€” axe 4.11
  incorrectly rejects <li role="group"> inside <ul role="listbox">
  which is valid per ARIA 1.2
- Disable label rule in Application.open() check for pages that may
  transiently render Keycloak's OTP setup form
- Remove stale post-navigation check in createFileFromTemplate
  sidebar branch (sidebar is unmounted before check runs)
2026-07-20 06:36:49 +02:00
Matteo
5bf887a570 Chore/fix e2e violation (#12526)
* fix(e2e): resolve admin-settings general spec violations

- prevent focusable elements inside hidden breadcrumb items
- make OcDrop tippy role configurable, default to none
- wait for logo-wrapper element after page reload in e2e

* fix(e2e): resolve admin-settings groups spec violations

- add aria-label to the icon-only groups filter-confirm button, which
  had no name for screen readers to announce
- set reducedMotion on e2e browser contexts so notification fade-in
  animations don't race axe scans and produce false color-contrast
  failures
- fix tippbBox selector typo (-> tippyBox) that made the scan on the
  group context menu throw instead of running
- fix groupList and editPanel selectors in the shared selector map:
  groupList pointed at a nonexistent class, and editPanel used the
  non-standard :visible pseudo-selector which is invalid in native
  querySelectorAll

* fix(e2e): skip tooltip fade transition under reduced motion

Plain tooltips (v-oc-tooltip) use tippy.js's default fade animation
and default #333/#fff colors, driven by tippy's own duration option
rather than a CSS transition. Setting reducedMotion on the Playwright
browser context does not stop this, since tippy's animation ignores
prefers-reduced-motion on its own. Axe scans could catch the tooltip
mid-fade, when the text is still low-opacity, and report a false
color-contrast violation. Now the duration is forced to 0 when the
media query matches, mirroring how oc-fade-in already handles this
for CSS-driven animations.

* fix(e2e): resolve officeSuites spec progressbar violation and test bugs

- add aria-label to the global loading progress bar, which had no name
- point the space quota progress bar at its existing text label via
  aria-labelledby instead of leaving it unnamed
- fix a string-literal-instead-of-variable typo, an XPath selector that
  axe can't use (only CSS), and a scan that ran after clicking closed
  the element it was targeting, all in the public link test helpers
- move the create-document-modal scan to after the modal actually
  opens, since it was scanning too early and finding nothing

* fix(e2e): resolve app-store details spec contrast violation and scan bug

- override md-editor-v3's default link and inline-code colors in the
  read-only markdown preview, which didn't meet WCAG AA contrast
  against the app card background
- point the download-app a11y scan at the app list page instead of a
  details-page selector that isn't present on that page, a leftover
  from copying the sibling download-version helper

* fix(e2e): resolve participantManagement pagination spec violations

- patch vue-select to render aria-controls on its combobox toggle,
  which it already computed internally but never attached to the
  element with role="combobox"
- add aria-label to the account menu quota bar and upload progress
  bar, both missing a name on their progressbar role, same gap fixed
  earlier in LoadingIndicator/SpaceQuota
- add aria-label to the file-details preview-loading spinner, which
  rendered role="img" with an empty aria-label
- stop scanning the sidebar actions panel in deleteResource after it
  was already closed, which made the scan throw instead of running

* fix(e2e): add missing aria-label to hide-share quick action button

The icon-only hide/unhide-share button in the shared-with-me table had
a tooltip but no aria-label, so it had no accessible name. Reused the
label already computed for the tooltip instead of duplicating it.

* fix(e2e): fix sidebarPanel selector typo in downloadResources

Used the string 'sidebarPanel', which isn't a key in the shared a11y
selector map, so it fell through to being used as a literal (and
broken) CSS selector. Switched to the existing appSidebar key, which
resolves to the same #app-sidebar selector already used for this
concept elsewhere.

* fix(e2e): add accessible name to markdown editor's content area

md-editor-v3's underlying CodeMirror instance renders its editable
content div with role="textbox" but no accessible name, and the
library exposes no prop to pass one through. Set aria-label on it
directly after mount, since that's the only available hook.

* fix(e2e): fix users-filter button label and navigate scan selector

- add aria-label to the icon-only users search/filter-confirm button,
  the same button-name gap already fixed for the groups page
- fix Users.navigate scanning appSidebar, which isn't rendered until a
  sidebar panel is actually opened; switched to scanning body, matching
  the working pattern already used by Groups.navigate

* fix(e2e): fix global search dropdown ARIA structure and scan bugs

- restructure the search results listbox so its direct children are
  valid group/option roles instead of plain nested <li>/<ul>, fixing
  aria-required-children/parent, list, and listitem violations
- give the loading/no-results states no listbox role at all, since
  they're informational text rather than actual options
- give the listbox an accessible name via the existing search label
- fix the icon-only "search options" listbox missing aria-controls
  becoming null instead of a static string when the dropdown isn't
  rendered
- add a disableRules option to assertNoSevereA11yViolations, using it
  for two narrow, investigated cases: search-result rows render a real
  <a href> so native middle-click/ctrl-click "open in new tab" keeps
  working (nested-interactive can't be satisfied without removing
  that), and a checkbox nested in a clickable filter-list button that
  would otherwise lose its only accessible selection-state indicator
- fix the same aria-controls transient-timing gap in two more call
  sites that hit it after a route change (closing the editor, opening
  any app via the app switcher)

* fix(e2e): fix low contrast search input in select combobox

vue-select's vendor CSS dims the search input to 20% opacity while
searching but not yet open, dropping text contrast to 1.51:1 against
the required 4.5:1. Override the opacity back to 1 for that state.

* fix(e2e): add labels to app gallery navigation buttons

The prev/next/set-image buttons in the app details image gallery only
render a decorative icon with no text or label, leaving them with no
discernible name for screen reader users.

* fix(e2e): add label to clear-clipboard button in files app bar

The clear-clipboard button next to "Paste here" only renders a
decorative close icon with no text or label, leaving it with no
discernible name for screen reader users.

* fix(e2e): add label to generic app-loading spinner

The spinner shown while an external app is loading has no aria-label,
leaving the role="img" element with no accessible name even though a
visually-hidden "Loading app" text already exists right next to it.

* fix(e2e): add label to GDPR export loading spinner

The spinner shown while the GDPR export status is loading has no
aria-label, leaving the role="img" element with no accessible name.

* fix(e2e): fix combobox aria attributes in create shortcut modal

The suggestion dropdown had no explicit toggle target, so tippy fell
back to the input wrapper div and set aria-expanded on an element with
no ARIA role. Point the drop at the actual input and give it proper
combobox semantics.

* fix(e2e): fix users filter checkbox-button scan and delete selector bug

Suppress the already-accepted checkbox-in-button nested-interactive
rule at the two roles filter scan sites in filterUsers, matching the
pattern used elsewhere for the same ItemFilter.vue markup. Also fix a
string-literal selector in deleteUserUsingContextMenu that was never
actually calling util.format, so axe scanned for a nonexistent element.

* fix(e2e): resolve admin-settings spaces spec violations

- replace removed #files-toggle-sidebar with the "Show details" button
  (that button now opens the sidebar in one click; selecting via the
  checkbox first would toggle the space off when Show details toggles it on)
- fix broken scan selectors: 'appSidebarDiv' -> 'appSidebar' (not a key in
  the selectors map, was silently falling through to the literal string);
  'tippyBox' -> 'ocModal' at the confirm-action scan (the modal is what's
  actually rendered there, not a tippy); 'filesView' -> 'adminSettingsWrapper'
  in performSpaceAction (this runs on the admin-settings page, not files)
- wrap transitionend waits in Promise.all with their triggering click, so
  the listener attaches before the transition begins - otherwise a near-
  instant transition (under prefers-reduced-motion: reduce, enabled by an
  earlier fix in this branch) can finish before the listener binds and
  the wait never resolves, hanging the "list members via sidebar" test

* fix(e2e): mark kindergarten journey test as slow

The journey performs 16 downloads plus shares and deletes, each cycling
the sidebar with a11y scans, and consistently runs 3-4 minutes even in
isolation - past the default 180s timeout. When the deadline hits, the
axe scan in flight fails with "Target page, context or browser has been
closed" from a different call site each run.

test.slow() triples the timeout to 540s, the idiomatic Playwright hint
for legitimately long journey tests.

* fix(e2e): add aria-label to create-user button when icon-only

When admin-settings shrinks to a limited-width viewport, the create-user
button collapses to icon-only and its visible text label is hidden. The
tooltip already switches to the accessible name in that mode; mirror
that on aria-label so the button retains an accessible name in the
collapsed state (WCAG 4.1.2).

* fix(e2e): import expect in crashPage step helpers

expectCrashPageHasNoAccessibilityViolations uses expect() but the
import only included Page - the file wouldn't compile if that helper
was referenced anywhere.

* fix(e2e): pass selector variables to admin-settings users a11y scans

Four call sites passed string keys ('loginToggleWithDropdown',
'loginDropDown', 'groupsModalInput') that don't exist in the shared
selectors map - assertNoSevereA11yViolations' fallback then used those
literal strings as raw CSS selectors, matching nothing, so axe threw
"No elements found for include" instead of actually scanning. Same
class of bug as the earlier 'tippbBox'/'sidebarPanel'/'linkUpdateDialog'
fixes in this branch.

Switched to passing the local const variables directly, which resolve
to the real CSS selectors defined in the same file.

* fix(e2e): scan notifications dropdown container instead of message list

Both notification-related scans passed notificationItemsMessages, which
is a selector that matches multiple elements (one per notification). axe
throws on multi-match includes. Switched to notificationsDrop, the
single container that wraps the message list.

* fix(e2e): wait for link-update dialog before scanning it

Four call sites (changeRole, changeName, addExpiration, deleteLink) ran
assertNoSevereA11yViolations on the linkUpdateDialog notification right
after the action that triggers it, without waiting for the notification
to actually appear - axe would race and sometimes scan before the DOM
was there.

Also fixed copyLinkToClipboard: previously scanned '.snackbar' (which
doesn't exist in this codebase) unconditionally; now waits for the
linkUpdateDialog and scans it, or for the password-protected-folder
case, waits inside the iframe and scans the iframe locator instead
(mirroring the pattern already used by open() in utils/sidebar.ts).

* fix(e2e): scan iframe locator for password-protected-folder sidebar

Two scans in the passwordProtectedFolder branch were pointed at
top-level page selectors ('tippyBox', the plain sidebarPanel const)
but that sidebar lives inside its own iframe (#iframe-folder-view),
not on the top-level page - so axe found nothing to scan and threw.

Switched to scanning the iframe locator itself. In open()'s post-open
scan, made the target conditional so the non-iframe branch keeps
scanning #app-sidebar as before.

* fix(e2e): drop premature tippyBox scan before more-options dropdown opens

createShare scanned the tippyBox before clicking showMoreOptionsButton,
but the tippy isn't in the DOM yet at that point - the click on the
button is what opens it. The second scan a couple of lines below runs
after the click, when the dropdown is actually rendered, which is the
only place the scan belongs.

* fix(e2e): scan body in shared createSpace instead of #files-view

createSpace is invoked from both the Files app spaces view (which has
#files-view) and the admin-settings spaces page (which has
#admin-settings-wrapper instead) - scanning a single view-specific
root failed in one of the two callers. Scan the always-present body
so both callers work.

* fix(e2e): make resource-action a11y scans robust to timing and view mode

- clickResource: it's used for both folder navigation (breadcrumb
  appears) and file-open (navigates away into a viewer/editor with no
  breadcrumb). The unconditional post-click scan of 'breadcrumb' timed
  out on file opens. Wait for the breadcrumb with a 5s cap and skip
  the scan when it never appears.
- createNewFolder: was scanning 'filesSpaceTable' which only exists in
  table view. Scan the view-mode-agnostic 'filesView' wrapper instead.
- downloadResources / pasteResource / moveOrCopyResource: add waitFor
  on the target selector before axe scans it, otherwise axe can race
  and scan before the DOM updates from the preceding click.

* fix(web-app-app-store): fix TS2322 type error in AppImageGallery aria-label
2026-07-13 07:50:03 +02:00
Lukas Hirt
6bad03d364 [full-ci] chore: [OCISDEV-5] merge and relicense ownCloud Web into oCIS (#12491)
* chore: [OCISDEV-5] Merge and relicense ownCloud Web into oCIS

Consolidate the ownCloud Web frontend into this repository as a single
product with one contribution surface and one license. The web/ source
is imported as-is from the final standalone owncloud/web release
(v12.5.0 / last-agpl-release @ b16a34fdf5569d2fd63b1ff3c575c1a4ee569ad3);
the archived owncloud/web repository remains the historical record for
everything at and before that commit.

Relicensing:
- All web/ contributors have signed the ownCloud CLA, granting ownCloud
  GmbH the right to relicense their contributions.
- web/LICENSE (AGPL-3.0) removed; the repository root LICENSE
  (Apache-2.0) now governs web/ as well, matching how the rest of the
  repo is already licensed.
- All 25 web/packages/*/package.json license fields flipped to
  Apache-2.0; root NOTICE added documenting the relicensing provenance.
- Added REUSE.toml + LICENSES/ so the whole repository (including
  vendored Go dependencies) is REUSE 3.3 compliant.

CI/build:
- services/web/Makefile now builds web assets from the in-tree source
  instead of downloading a release tarball from owncloud/web; license
  checking/saving likewise runs against the in-tree source.
- ci.env and tests/acceptance/run-e2e.py no longer clone owncloud/web
  for Playwright e2e tests.
- Added the app-provider and ocm e2e suites to acceptance-tests.yml's
  matrix, closing a coverage gap where they were silently excluded;
  ported the Collabora/OnlyOffice/federated-instance orchestration
  web's old CI used to run them.
- Added web-tests.yml (typecheck/format/lint/unit-test), a
  check-licenses.yml, commit-message.yml, and release-npm-packages.yml
  for the @ownclouders/* packages, replacing web's old standalone CI.
- Removed dead CI tooling inherited from the standalone repo
  (web/tests/drone, web/tests/actions, web/.github, and an orphaned
  ci.env-dependent cache-check script).

Docs:
- Rewrote docs/services/web/releasing.md and web/docs/releasing to
  describe the in-tree build/release process.
- Updated remaining references to github.com/owncloud/web across docs,
  services/web/README.md, and the deployment example to point at the
  in-tree web/ directory.

Signed-off-by: Lukas Hirt <info@hirt.cz>

* ci: sync web/ translations via Transifex

web/ is a pnpm workspace nested inside the repo, so it isn't covered by
the existing translation-sync job (sub_path: ., no package.json at the
repo root). Add a second sync-web job invoking the same reusable
workflow with sub_path: web and package_manager: pnpm, so its l10n-read/
push/pull/write targets actually install web's dependencies instead of
silently running against an empty node_modules. Sequenced after the
existing sync job since both push to the same hardcoded
chore/translations-update branch.

* ci: fix pnpm cache setup order in web-tests and check-licenses

actions/setup-node's cache: pnpm input shells out to pnpm to resolve
the cache directory, so pnpm must already be on PATH when that step
runs. Both workflows ran `corepack enable` *after* setup-node, which
still failed: corepack writes its pnpm shim into the currently active
Node installation's bin dir, and setup-node had already swapped PATH
to the newly-installed Node version by that point, leaving the shim
behind. Use pnpm/action-setup instead, which installs a standalone
pnpm binary independent of the Node version, before setup-node runs.

Also set cache-dependency-path explicitly: the lockfile lives at
web/pnpm-lock.yaml, and cache-dependency-path resolves relative to
GITHUB_WORKSPACE regardless of the job's working-directory default
(that default only applies to run: steps, not to setup-node itself).

* fix(web): resolve 19 HIGH trivy findings in pnpm-lock.yaml

All 19 findings had fixes available upstream, so per this repo's own
.trivyignore policy (reserved for cases with no fix available), these
get fixed rather than suppressed.

vite (7.3.2 -> 7.3.5) is a direct dependency, bumped directly in every
package.json that pins it.

The other 8 (@xmldom/xmldom, flatted, form-data, immutable, js-cookie,
linkify-it, minimatch, ws) are purely transitive. Verified empirically
that `pnpm update <pkg>` silently no-ops on packages not declared in
any workspace manifest, even when a parent's semver range would allow
the fix (e.g. glob@10.5.0's `^9.0.4` covers 9.0.7) -- so pnpm.overrides
is genuinely required here, not just convenient.

minimatch is overridden with a version-range key
(minimatch@>=9.0.0 <9.0.7) rather than a blanket override, since 6
different major versions of minimatch coexist in the tree for
different consumers (3.x/5.x/10.x elsewhere); a blanket override would
have forced all of them to 9.0.7 and likely broken callers expecting a
different major's API.

* fix(web): unify @types/node resolution to stop duplicate vite types

The previous vite 7.3.2 -> 7.3.5 bump caused pnpm to resolve two
different @types/node versions (25.7.0 and 26.1.0) as vite's optional
peer across different workspace packages. vue-tsc then saw two
structurally-different copies of vite's types (e.g. Plugin, HotUpdateOptions)
and failed with TS2769 in design-system, web-client, web-pkg and
web-test-helpers' vite.config.ts files.

Force a single resolution via pnpm.overrides, pinned to 24.13.2 to
match the Node 24 runtime (engines/volta) rather than an arbitrary
newer major.

* fix(tests): fix ocm/app-provider e2e suites' oCIS orchestration

Both suites were newly wired up by the previous merge-web-repo commit
and hadn't run against real CI yet, so their setup had two latent bugs:

e2e-ocm: the federated instance's env only offset *_DEBUG_ADDR ports,
leaving the actual service ports (e.g. gateway's default
127.0.0.1:9142) unset. The federated "ocis server" process then
crashed trying to bind the same ports the primary instance already
held. run-github.py's Behat apiOcm suite already solved this with a
canonical tests/config/local/.env-federation port map (proven working,
since apiOcm passes) -- reuse it instead of the ad-hoc offset. Also
adds OCIS_ADD_RUN_SERVICES=ocm/OCIS_ENABLE_OCM, missing from the
primary instance too.

e2e-app-provider: tests/config/ci/app-registry.yaml maps its one
mimetype to "FakeOffice" (the stub used by apiCollaboration) and has
no docx entry at all, so the real Collabora/OnlyOffice containers this
suite drives never appeared in the web UI's "New file" menu. Add a
dedicated app-registry mapping both odt->Collabora and docx->OnlyOffice
with allow_creation, and use it only when COLLABORATION_NEEDED is set.

Signed-off-by: Lukas Hirt <info@hirt.cz>

* fix(tests): trust federated oCIS cert, register office templates by target_ext

e2e-ocm: the primary and federated instances each generate their own
self-signed proxy cert. Only the primary's was ever added to the
system CA trust store, so Chromium refused the federated instance's
TLS handshake ("tls: unknown certificate") once federation began.
Trust the federated cert too, and thread OCIS_BASE_DATA_PATH through
its `ocis init` call (previously only set for the running server),
since that's where the cert actually gets written.

e2e-app-provider: reproduced the suite locally (real Collabora/
OnlyOffice containers + `ocis collaboration server`) and diffed
`/app/list` before/after. allow_creation and default_app alone don't
make the web UI's "New file" menu show an entry -- it additionally
requires app_providers[].target_ext, which reva's app-provider only
stamps onto a hardcoded set of "-template" mimetypes
(vendor/github.com/owncloud/reva/v2/.../appprovider/templates.go), not
the plain document mimetypes the previous config used. Existing odt/
docx files still open fine without a static entry, since Collabora/
OnlyOffice register their full supported mimetype list dynamically via
WOPI discovery -- it's specifically file *creation* that needs this.

Signed-off-by: Lukas Hirt <info@hirt.cz>

* fix(changelog): shorten title over the 80-char lint limit

changelog/unreleased/bugfix-personal-space-fail-closed.md landed on
master (#12442) with a 97-char title, which changelog-lint rejects.
GitHub tests PRs against a merge with the current master tip, so this
started failing build-and-test on every open PR once master picked up
that commit -- unrelated to this branch's own changes. Fixing it here
since master needed to be merged in anyway.

* fix(tests): load web apps the ocm/app-provider e2e suites depend on

Both suites drive the web UI, and web only loads the web apps listed in
its UI config's "apps" array. run-e2e.py reuses
tests/config/ci/ocis-config.json, which predates the playwright suites
and lists neither app they need, so both failed deterministically while
the API-only Behat suites (apiOcm, apiCollaboration) kept passing:

e2e-ocm: the "open-cloud-mesh" app menu item can never render because
"ocm" was missing, so web-app-ocm was never loaded. Add it for the
federated suite. Behind that sat a second bug: the invite flow embeds
token@<BASE_URL_OCIS host> (127.0.0.1:9200) into invite codes, but the
federated instance authorizes providers against
tests/config/local/providers.json, which only lists localhost:9200.
Address the primary as https://localhost:9200 when federated, mirroring
run-github.py's passing apiOcm setup (the self-signed cert covers both
hosts; other suites keep 127.0.0.1).

e2e-app-provider: web-runtime only builds the per-provider Collabora/
OnlyOffice editor apps -- including their "New file" menu entries --
when web-app-external is loaded (web/packages/web-runtime/src/index.ts
gates on applicationStore.has('web-app-external')), and "external" was
missing. This also falsifies the previous target_ext theory: the
template-mimetype registry was active in the failing run and the menu
still never appeared, because the New-file menu needs only
allow_creation plus a registered provider
(web-app-external/src/index.ts). Revert the app registry to the plain
odt->Collabora / docx->OnlyOffice mimetypes web's own e2e CI proved out
(web/dev/docker/ocis/app-registry.yaml). Create-from-template still
works without static entries: reva stamps target_ext onto the -template
mimetypes the providers register via WOPI discovery.

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: upload playwright traces and a11y report from e2e suites

Port the two upload-artifact steps the standalone web repo's e2e
workflow had: playwright error contexts/report output on failure, and
the a11y report on any non-cancelled run. Paths are prefixed with web/
since the web repo now lives in that subdirectory, artifact names use
the suite name instead of the job index, and the action pin matches the
one already used in this workflow.

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(tests): allow office editor iframes in the e2e proxy CSP

The app-provider suite got past file creation but every office test
then timed out waiting for the editor to render: ocis's default proxy
CSP only allows frame-src 'self' (exact scheme+host+port), so the
browser refused to embed the Collabora/OnlyOffice iframes served on
other ports. The COLLABORA_DOMAIN/ONLYOFFICE_DOMAIN env vars do nothing
on their own -- they are only substituted into a custom CSP file, which
is why the pre-merge web CI always set PROXY_CSP_CONFIG_FILE_LOCATION
(tests/drone/csp.yaml there). The localStorage SecurityError seen in
the logs was a downstream symptom: the CSP-blocked frame ends up with
an opaque origin where storage access throws.

Add the two editor domains to tests/config/ci/csp.yaml's frame-src and
img-src (mirroring web's proven csp.yaml) and point the collaboration
suite at it. The keycloak suite shares this file; for it the new
entries fall back to nonexistent default hosts and are inert.

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(licenses): attribute REUSE.toml copyright to ownCloud contributors

The web/ tree carries community contributions dating back to 2016; the
CLA grants a relicensing right, not a copyright transfer, so declaring
sole 2020-2026 ownCloud GmbH authorship was inaccurate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(tests): trust the Keycloak cert in e2e TLS setup

The Keycloak cert had no SAN, and NODE_EXTRA_CA_CERTS only ever pointed
at the oCIS cert, so any node-fetch/axios call made directly against
Keycloak (admin token fetch, user provisioning) failed TLS validation
and aborted the keycloak/mfa matrix jobs before a spec could run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(web): don't wipe assets/ before a successful build

build-assets ran `git clean -xfd assets` before the pnpm build; a failed
typecheck or vite build left assets/core/ empty, so the next Go embed or
docker deployment served no web UI. Clean only after the build succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* ci: fail clearly when a release tag matches no known package

If the tag-prefix loop found no match, the workflow silently fell
through to a jq lookup against "packages//package.json", failing with a
confusing path error instead of naming the problem.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* ci: drop duplicate dependency-license-check job

web-tests.yml already enforces the license allow-list via
`pnpm licenses:check` (license-checker-rseidelsohn) on every PR.
check-licenses.yml's dependency-license-check ran a second, differently
configured tool (npx license-checker, GPL/AGPL deny-list only), which
could disagree with the first without adding coverage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Signed-off-by: Lukas Hirt <info@hirt.cz>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 10:37:00 +02:00