Repository navigation
Release: merge development into beta - #712
Open
github-actions[bot] wants to merge 300 commits into
Open
github-actions[bot] wants to merge 300 commits into
github-actions[bot] wants to merge 300 commits into
Conversation
…260912131600 chore(sync): carry beta back into development
The dev box runs one shared Nextcloud on localhost:8080 that bind-mounts everybody's checkouts. This suite creates applications, schemas, pages and RBAC users, so aiming at that instance now has to be said out loud. tests/e2e/shared-instance.ts holds the guard and resolveE2EBaseURL() passes the resolved target through it. A run on localhost:80 or localhost:8080 stops with an explanation unless BUILDIQ_E2E_ALLOW_SHARED_INSTANCE or E2E_ALLOW_SHARED_INSTANCE names that exact origin. CI is exempt: there localhost:8080 is the runner's own throwaway instance. Guarding the resolver alone would have covered almost nothing here, because 21 other places computed their own target. The root playwright.config.ts, global-setup.ts, workflows/fixtures.ts and 18 spec files each carried a private process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:8080'. They now import the resolver, which is the convention the other specs in this suite already follow. github-store.spec.ts keeps its own constant: that one is BUILDIQ_GITHUB_STORE_URL and it points at a store, not at the app under test. The unit test lives in tests/vitest/ because vitest.config.js excludes tests/e2e/**, and because Playwright's default testMatch would otherwise collect it and report an empty suite.
…60912205055 chore(release): 0.7.8-unstable.20260912205055
… it (#767) * fix(register): resolve buildiq's own register slug instead of pinning it ExportsController's IDOR guard and slug lookup, and AppRepoSerializer's automations read, named 'buildiq' as a literal. On an instance that has not run the rename from openbuild they matched no register row and failed in silence: the owner was denied with no log line, and the published repository shipped an empty automations section. Both now ask the register-slug resolver, and the pin guard learns the positional searchObjectsBySlug shape. * fix(exports): probe the slug resolver with interface_exists, and name the test arguments class_exists() is false for an interface, so ownRegisterSlug() returned null on every instance and the export routes denied every non-admin owner. Four ExportsControllerTest cases caught it as 403 where 422 or 202 was expected. The new and touched test calls also use named arguments, as the phpcs sniff requires. * fix(register): keep the own-register resolution inside the phpmd limits The warning branch pushed collectAutomations() past NPath 200 and the class past 1000 lines, and the comment pushed isAuthorisedForApplication() past 100 lines. The resolution now joins the existing early return, with the canonical slug inline. OwnRegisterResolutionTest still reddens on a reinstated literal.
ApplicationDetailActions.vue now renders its whole action cluster through CnActionButtons (inline: 2), which promotes Settings + Edit to standalone header buttons and folds everything else (Export, Save as template, GitHub, permissions, Delete) into a single "···" overflow menu. Several e2e specs still assumed the old shape — Settings as an overflow menuitem, Export as its own always-visible button — and never got updated alongside the refactor, so they failed once the Playwright E2E job could actually run (it had been failing at Install Playwright before any test executed). - export-flows-and-agents.spec.ts, buildiq-runtime.spec.ts (x2): Settings is now a top-level button (`data-testid="cn-action-app-settings-action"`), not a menuitem behind "Actions". - export-zip.spec.ts: Export now lives in the "···" overflow menu, so the test opens it first. - save-as-template.spec.ts: target the action by data-testid instead of an unscoped role query (rules out collision with CnDetailPage's own, separate "Actions" menu), and pad the dialog's visibility timeout past its three chained requests. - application-detail-overview.spec.ts (REQ-OBADO-006): NcButton renders an anchor once given an href, so "Open in OpenRegister" is now role "link", not "button" — matches RegisterWidget.vue's accessibility fix below. Also fixes a real gap the refactor exposed: RegisterWidget's "Open in OpenRegister" link was previously a plain click handler doing `window.location.href`, so it never matched the `a[href]` selector the "structural widget deep-links preserve ?_version=" test scans, and that test always skipped as vacuous (zero anchors found). Converting the button to a real `href` (already done, for accessibility) made the test actually run for the first time — and it caught that a version sharing production's register carries no version marker at all. openRegisterUrl now appends `?_version=` for a non-empty versionSlug, matching the convention the Schemas/Pages/Menu widgets already use via buildVersionedRoute. Two other failures on this branch (REQ-OBR-006a's page-context-closed error, and an earlier save-as-template timeout before this padding) look like CI timing/resource flakiness late in the single-worker 30-minute E2E run rather than something traceable to this diff — worth a re-run before digging further.
OwnRegisterResolutionTest (merged in via development) exercises
AppRepoSerializer, which constructs AppRepoPayloadSafety as a default
collaborator. Two of the four tests execute that collaborator's code without
it being declared anywhere on the class, so PHPUnit's
checkForUnintentionallyCoveredCode flags them risky ("OK, but there were
issues!") on the one CI leg that runs with coverage enabled — same pattern
as the existing @uses entries for TemplateRepoSerializer and
FakeSlugResolver, just missing this one.
…v, l10n - ApplicationDeletionService: compare schema references by string instead of (int) casting, and resolve slug entries via findIdsBySlugs() so a schema shared by id in one register and by slug in another is still recognised. Hoist the register scan out of the per-version loop so it runs once per teardown instead of once per version. - Sync the hand-maintained OpenRegister test stub's SchemaMapper with findIdsBySlugs(), which the real class already has. - PreviewSandbox: block real anchor navigation (the sandbox's memory router only intercepts RouterLink clicks, so a plain `<a href>` was taking the whole designer with it) unless target="_blank"; the click still bubbles so RouterLink's own navigation keeps working. Match CnWalkthrough's convention of nulling non-reactive instance fields in created(). - Add the 5 missing Dutch translations for the new dashboard KPI-link aria-labels and the walkthrough designer's tab aria-label.
PreviewSandbox: blockActivation's capture-phase handler was calling preventDefault() on every anchor, including RouterLink ones — vue-router's guardEvent() bails on a defaultPrevented event, so in-preview nav menus stopped navigating. Anchors are now decided in a bubble-phase blockAnchorNavigation, using event.defaultPrevented to tell a handled RouterLink click from a plain one, with no RouterLink detection needed. Added a test mounting a real RouterLink to pin this. ApplicationDeletionService: the prior fix's slug-resolution additions pushed the class over phpmd's ExcessiveClassComplexity threshold. Extracted the reference-checking logic into SchemaReferenceResolver. ApplicationDetailActions: corrected a stale comment claiming the promoted action pair is always Settings + Edit — both entries are conditional, so a non-owner promotes a different pair. PreviewSandbox.vue also needed a missing @SPEC tag on created() (caught by gate-16 once the surrounding diff brought it into scope), and both touched spec files needed a prettier pass.
* docs(openspec): extend the case-type layout to CT-6's tabs, widgets, header, task list and upload fields Round 4 discovery cluster CT-6, rows B16 and C16, matrix 11.6, 11.7 and 11.8, plus D-casetype-21, D-casetype-22 and D-casetype-26 from the second read. Decision D16 puts the layout here and the field flag on the field. Adds REQ-OBPL-004 to REQ-OBPL-009. Size L. dossiq consumes the leaf. * docs(openspec): give a form its intake channel, its order and its sections Round 4 discovery cluster CT-6, rows C13 and B16, matrix row 1.1, plus candidate C-intake-16 whose portal half stays with cluster 51. Decision D16: the form carries which fields appear in which order for which channel. Adds REQ-OBRF-007 to REQ-OBRF-009. Size M. dossiq writes the channel from the served form. * docs(openspec): index buildiq's competitor parity changes under one umbrella buildiq owns no cluster of the 70 and one of the depth study's nine: CT-6, the form is not a form, size L, wave 3. Both parity changes carry it. Documentation only, nothing is implemented.
Includes nextcloud-vue#1047, which ApplicationDetailActions depends on (inline, children, href, onSelect, openEditForm). The only breaking change in the 2.53.1..3.0.0 range removes CnNewsWidget/the news widget type, which buildiq does not use.
…oud when its base moves (#773)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
) #533 made buildiq.conduction.nl the canonical docs host and turned openbuild.conduction.nl into a 301 to it. The app and the docs site itself still named the retired host: docusaurus url, docs/static/CNAME, llms.txt, the Documentation action on an application, and ten documentationUrl entries in the manifest. Every one of those links cost a redirect, and the docs site's canonical URL pointed at a host that only redirects. The two tests that pinned the old host now pin the new one. Ported from 355b043 on feat/rename-register-slug-to-buildiq, which landed after #423 merged. The openspec beta-surface-alignment change keeps its historical wording. Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
…istry (#777) * docs(openspec): adopt the connection registry * feat(connections): declare the store, GitHub, document and webhook connections * feat(connections): add the Integrations page over integriq's registry * feat(connections): report store, GitHub, document and webhook outcomes, refresh on a store save * fix(connections): hand the reporter to the hand-built SettingsService * test(e2e): cover the Integrations page and install integriq in CI * style(connections): meet phpcs on the new lines * docs(app): quote the package name so the JSDoc lint stops reading it as a tag
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
3.1.0 carries the walkthrough click-step fix (nextcloud-vue#1058), the webroot-prefixed component fetches (#1106) and the connection status 'limited' formatter (#1165). The range moves to ^3.1.0 so a fresh install cannot resolve back to 3.0.0 without them.
…egistry files (#786) simplexml_load_file() returns false under the Nextcloud bootstrap because lib/base.php installs a libxml external entity loader that returns null, and that resolver also handles the primary document. Reading the bytes and parsing a string never touches it. Also runs prettier over the files the connection registry wave merged unformatted.
…mport again (#790) Three properties declared their link with a bespoke x-openregister-relation {target, type} block and no $ref. openregister now reads that annotation as a typed label requiring $ref and a declared relation type, so it rejected built-app and applicationVersion at import while answering 200. Each now uses the canonical ADR-062 dialect. openregister's own validators pass the register (0 relation errors, 0 rejected); gates pass. The schema editor and four templates still emit the legacy shape: flagged for a decision.
…3.2.0 (#792) 3.2.0 ships connectionStatus and connectionSettingsLabel as built-ins, with disabled reading Switched off. CnAppRoot spreads the app's own formatters over the built-ins, so the local copy would have shadowed them. The spec now builds the registry from App.vue the way CnAppRoot does.
…anded (#784) * fix(demo-data): the example data lands, and the wizard reports what landed The setup wizard reported "Demo data installed: 18 objects" on an instance where OpenRegister had skipped all 18. Two independent causes: 1. The descriptor addressed schemas by NAME ("Application", "HelloMessage", "exportJob") while OpenRegister resolves them by SLUG ("built-app", "hello-message", "export-job"). buildiq is the case where the two differ, so 15 objects were skipped. Regenerated with the current hydra-gates generator, which emits slugs. 2. The three applicationVersion objects carried "manifest": {}, and the property is required, so each failed validation. They now carry a minimal manifest that satisfies the schema. And the reason nobody noticed: the count came from the FILE, so it repeated the request instead of reporting the result. install() now returns what the importer wrote or left unchanged, with the declared total and the skipped count beside it, and throws when a dataset declares objects and seeds none. The wizard says "Imported X of Y demo object(s)" and names the gap. * fix(demo-data): drop the empty objects OpenRegister refuses, nested ones included The first pass fixed the schema slugs and the top-level manifest, and the live import went from 0 of 18 to 15. The last three failed on `companionSchemas.0`: an empty object nested inside an array. OpenRegister refuses {} at any depth, so the dataset now carries none, at any depth. An empty element in an array carries nothing, so it is dropped rather than filled. An optional object property is omitted instead of set to null: the generator's --check types it as an object and refuses null, while OpenRegister refuses {} — omitting satisfies both. Live import on the shared instance: "Imported 18 of 18 demo object(s).", and every schema that shipped demo data now has it (hello-message 3, export-job 3, application-template 3 new, built-app 3, applicationVersion 3, built-app-route 3).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
#794) A fresh install stored no register, so /api/settings answered "register":"" and the admin page showed an empty field, while the admin tutorial says it is preset to buildiq. The default now resolves to the buildiq register, and a register saved as empty reads back as that default too.
…r for int-dutch-registries
docs(openspec): specs for the missing parts of half-built capabilities
Three ticked changes failed strict validation: two MODIFIED deltas dropped scenarios the main spec still has, one requirement body lacked SHALL/MUST. beta-surface-alignment and harden-xss-dos-csrf stay open: tasks the code no longer (or never effectively) meets are unticked with a note.
app-repo-format-v2 (main spec already carried its requirements, archived with --skip-specs), buildiq-consumes-shared-dmn, data-registers-runtime, data-registers-schema-declaration, fix-builder-nav-route-and-identity, fix-manifest-diff-insights-lookup (MODIFIED block now also carries the manifest-name scenarios fix-builder-nav-route-and-identity merged), fix-promote-rewires-target-version, harden-rules-authz-and-audit-parity.
layered-versioned-app-deltas, namespace-the-agent-schema-slug, openbuild-app-binds-flows-and-agents, openbuild-exports-flows-and-agents, openbuild-walkthrough-editor, schedules-editor, wizard-dataset-card-load. The four new main specs get a real Purpose instead of the archive's TBD. store-shows-built-in-templates stays open: its MODIFIED delta targets a requirement the main spec no longer has. app-delta-override's MODIFIED block now carries the manifest-endpoint scenarios batch 1 merged, so it still validates.
docs(openspec): archive pass, changes the code has delivered
Nextcloud's SecurityMiddleware honours the @NoCSRFRequired docblock as well as the attribute (hasAnnotationOrAttribute), so removing only the attribute left CSRF off on the settings writes. Drop the docblock annotation from the three state-changing routes: - settings#update (PUT /api/settings) - settings#create (POST /api/settings) - settings#load (POST /api/settings/load) settings#index (GET /api/settings) keeps both forms: it is a read-only JSON GET with no side effects, and a cross-site GET cannot read the response, so the exemption exposes nothing. Callers already send the token: the store's fetch calls set the requesttoken header, and the e2e specs and ci-seed.sh send OCS-APIRequest: true, which passesCSRFCheck() accepts. SettingsControllerCsrfTest asserts by reflection that update, create, load and PreferencesController::setPreference carry neither form, with index as the control that proves the detector sees both. Ticks tasks 3.1 and 3.3 of harden-xss-dos-csrf and archives the change (every task done); its eight ADDED requirements merge into the five existing capability specs.
store-shows-built-in-templates: delta rebased onto the current template-catalogue-ui main spec (RENAMED + MODIFIED gallery requirement, MODIFIED clone dialog requirement); archived. beta-surface-alignment: the openregister dependency scenario now matches the code (a comment, no <app> element, which the App Store schema rejects); tasks 2.3 and 4.x ticked. Left open: the product page shows v0.10 while info.xml is 0.7.x.
docs(openspec): fix deltas so built changes can archive
…ta-surface-alignment
spec(beta-alignment): archive beta-surface-alignment
fix(security): require the CSRF token on settings write routes
…new boards Every screen now points at canvas part 2 (QAAxpcsFKBCvDUGbQbwtCa). 32 of the 35 unreferenced Bq boards are mapped onto the rows they deliver; ops-admin-settings gets BqBeheerInstellingen.
docs(openspec): link capabilities to the split design canvas and its new boards
Rows app-support-note, ops-reports, pg-setup-wizard-designer for boards BqSupportBewerken, BqRapportages, BqSetupWizardOntwerper (decision 99). Changes apps-support-note-editor-saves and operate-report-download; main spec buildiq-reports written after the fact.
docs(openspec): rows and specs for capabilities the design canvas draws
Two changes for portaliq #1387: a typed command another app's server uses to evaluate a rule set it is allowed to call (int-decision-table-logic), and Dutch field formats in the form designer and the schema field editor (int-dutch-field-checks).
docs(openspec): buildiq halves of portaliq's open forms changes
chore(parity): normalise features in the capability matrix
chore(parity): every spec under a feature, every capability on a screen
chore(parity): every spec under a feature, every capability on a screen
…es register (decision 196) (#1100) * refactor(rules): decision tables live in OpenRegister's decision-tables register (decision 196) A rule set's decision table is stored in OpenRegister's register under buildiq.<organisation>.<rule-set-slug> and read through its DecisionTableStore. DecisionTableShape maps buildiq's authoring shape onto the stored shape and back; the editor saves through PUT /api/rules/{slug}/decision-table (admin). buildiq's DecisionTable schema and RuleEngineService::DECISION_TABLE_SCHEMA are gone; repair step MoveDecisionTablesToOpenRegister moves existing tables and then renames the old schema's slug. Needs openregister#4572. * test(e2e): name openregister as owner of the decision-table seed slug (gate 109)
… with its findings, publishing needs none (decisions 179, 189) (#1099) * spec: forms are valid against their destination (decision 179) Decision 179 (Ruben, 10 Oct 2026): a form submits into its destination object, with no in-between intake layer, and is valid against that object's schema when built. Cross-app change: hydra openspec/changes/form-submits-into-its-destination-object (ADR-117, hydra#748). Spec only. * spec: the destination check refuses from the first release (decision 181) Ruben answered Q9: no report-only release. A buildiq form with findings is not saved; every finding shows on its field. * wip(forms): destination check on registration forms, form pages and app publish (decisions 179, 189) * feat(forms): a draft form saves with its destination findings on its fields; publishing needs none (decisions 179, 189) * feat(forms): findings strings in en and nl, e2e over the real routes, phpcs clean * test(forms): the external access gate, the honeypot and the designer save over the destination check * style(forms): eslint on the findings code * style(forms): prettier on the findings code * fix(forms): only an app's editors may check its forms; psalm stub, phpmd and the copilot fixture follow the destination key * refactor(forms): one field's mapping entry in its own method (phpmd) * build(deps): require @conduction/nextcloud-vue ^2.81.0 for CnFormPage findings and honeypot; test a finding lands on its field * style(tests): format the findings spec
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated PR to sync development changes to beta for beta release.
Merging this PR will trigger the beta release workflow.