Skip to content

feat(portal): Resource Locator — rename, /resource-locator alias, private notes in a secured zone - #627

Merged
dwolfson merged 9 commits into
odpi:mainfrom
dwolfson:feat/resource-locator
Oct 14, 2026
Merged

dwolfson merged 9 commits into
odpi:mainfrom
dwolfson:feat/resource-locator

Conversation

@dwolfson

@dwolfson dwolfson commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Follows #625 (merged).

Rename

  • The page title, header, breadcrumb, Portal tile and messages now say Resource Locator.
  • The page now also answers at /resource-locator, and the Portal tile points there. /resource-browser still works, so existing links and saved favourites keep working. Links inside the page stay on whichever path it was opened from. Apache <Location> rules added for quickstart (proxy-locations.conf) and freshstart (fastapi-ssl.conf).
  • The /api/resource-browser/... paths are unchanged.

Resource Explorer account (quickstart secrets)

  • New resourceexplorernpa digital account in coco-user-directory.omsecrets (omagServer, governanceEngine and serverOperator groups), plus a Resource Explorer token entry in egeria-servers.omsecrets.
  • Also adds exchange-quickstart/coco-dags/data/dts_2026-09-29.csv, a public US Treasury Daily Treasury Statement extract used by the coco-dags.

Private notes: on, in a secured zone

  • Endpoints: GET/POST /resource/{guid}/private-notes. A private note is an entry in the user's own My Profile journal (journal-my-activity), tied to the resource through additionalProperties.resourceGUID. The Notes card has an "everyone / only me" choice.
  • journal-my-activity zones each entry ['<userId>'] only, and ignores initialClassifications. A userId zone only grants access (validateZoneAccess ignores zones that aren't secured), so on its own it hides nothing. The handler therefore re-zones each new entry to ['resource-explorer-private', '<userId>'], borrowing Resource Explorer's secured zone, which is defined in both the quickstart and freshstart user directories.
  • Verified on quickstart with direct REST (JournalEntry 8bec72e4): erinoverview reads it; peterprofile and garygeeke get 403 OPEN-METADATA-SECURITY-403-020 by GUID and no hits from feedback-manager search.
  • Each entry is then linked to its resource with an Actions relationship (resource = actionCause, end 1; JournalEntry, an Action subtype, end 2), as the Egeria team suggested. journal-my-activity can't take a cause, so the link is a Metadata Expert related-elements call. The user's own journal listing now shows what each entry is about. A resource's private notes are read through Asset Maker's elements/{guid}/sponsored/actions (the user's own JournalEntries only), with no full journal scan. That needs activity_status_list=None: pyegeria's default of IN_PROGRESS silently drops journal entries. Verified live: test entry 8bec72e4 was linked to "categories" (link e853edac). Erin sees it from the resource and in her journal with its cause; Peter and Gary get nothing.
  • If the link fails, the API returns 502: the note is saved and private but won't show on the resource.
  • The Egeria team has acknowledged a security-zone bug (work starts 2026-10-14). The re-zone step stays until that fix is verified (BACKLOG RL-1).
  • If the re-zone fails, the API returns 502 and says the note was saved but is not private. Each private note now reports zones and protected. Older entries with only the userId zone are shown as "other people can read it".
  • Delete is off: DELETE /private-notes/{note} returns 501. Egeria can't delete a journal entry: the asset delete and the Metadata Expert delete both give 400-008 (egeria-python ISSUE-146).
  • BACKLOG RL-1: when Egeria's journal fix lands, review the borrowed zone, re-enable delete, and clean up the test entries 8bec72e4 and fef83ed5.

Fix: Egeria Explorer's REST APIs view failed intermittently

  • /api/rest-apis fetched the platform's OpenAPI spec with the browser's X-Egeria-Token. When that token had expired and the spec cache was cold (after its one-hour TTL or an app restart), Egeria answered 401 on every path and the endpoint returned 502. egeriaFetch renews only on a 401, so the view stayed broken.
  • The spec is the same for every user, so the fetch now retries once with the server's own login on a 401. Failures are logged as warnings, and the 502 detail lists what each path answered. Reproduced with a cleared cache and an invalid token: 502 before, 200 after. Mirrored to freshstart.

Dr.Egeria templates

Testing

  • 78 Resource Browser tests pass (quickstart and freshstart copies).
  • Live on quickstart: GET private-notes as erinoverview returns linked entry 8bec72e4 (protected: true); as peterprofile it returns nothing. Older unlinked test entries no longer appear. DELETE returns 501 without calling Egeria. I didn't POST a new private note through the UI, since it couldn't be deleted afterwards. The re-zone call itself was verified by REST (above).
  • I checked the renamed page and the Portal tile on quickstart, with no console errors.
  • On quickstart through Apache (after httpd -t and a graceful reload): /resource-locator, /resource-locator?guid=… and /resource-browser all return 200, and the Portal tile links to /resource-locator.

🤖 Generated with Claude Code

…ivate notes held back

- Rename: the page title, header, breadcrumb, Portal tile and messages
  now say Resource Locator. The /resource-browser address and the
  /api/resource-browser paths are unchanged, so links, favourites and
  the Apache proxy rules keep working.
- Private notes: endpoints that keep a note in the user's own My Profile
  journal (journal-my-activity), tied to the resource by
  additionalProperties.resourceGUID, plus the "only me" choice in the
  Notes card. Switched off in the page (PRIVATE_NOTES_ENABLED = false):
  on quickstart the entry carries zoneMembership [userId], yet other
  users read it directly from Egeria, because a userId zone only grants
  access and denies no one without a secured zone beside it. Egeria also
  has no supported delete for a single journal entry.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson dwolfson self-assigned this Oct 13, 2026
…DTS sample data

Adds the resourceexplorernpa digital account to the CoCo user directory
(omagServer, governanceEngine and serverOperator groups) and a Resource
Explorer token entry in egeria-servers.omsecrets so the Resource
Explorer can obtain its own bearer token. Also adds a Daily Treasury
Statement extract (public US Treasury data) used by the coco-dags.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
The page now answers at /resource-locator as well as the original
/resource-browser, so existing bookmarks and saved favourites keep
working. Links inside the page stay on whichever path it was opened
from. The portal tile points at the new name. Apache proxy rules added
for quickstart and freshstart. API paths are unchanged
(/api/resource-browser).

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson dwolfson changed the title feat(portal): rename the Resource Browser to the Resource Locator; private notes held back feat(portal): Resource Locator — rename, /resource-locator alias, Resource Explorer account; private notes held back Oct 13, 2026
…ed zone

journal-my-activity zones each entry with the userId only, and ignores
initialClassifications. A userId zone only grants access, so on its own
it hides nothing. Each new private note is now re-zoned to
[resource-explorer-private, <userId>]: the secured zone denies everyone
else, and the userId zone lets the author in. Verified on quickstart
(JournalEntry 8bec72e4): the author reads it, other users get 403 and
no search hits.

- If the re-zone fails, the API returns 502 and says plainly that the
  note was saved but is not private.
- Each private note now reports its zones and whether it is protected.
  Older entries that carry only the userId zone are shown as readable by
  other people.
- Delete is off (the route returns 501): Egeria cannot delete a journal
  entry (egeria-python ISSUE-146), and pyegeria's remove_note must not
  be called.
- BACKLOG RL-1: review the borrowed RE zone, delete and cleanup once
  Egeria's journal fix lands.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson dwolfson changed the title feat(portal): Resource Locator — rename, /resource-locator alias, Resource Explorer account; private notes held back feat(portal): Resource Locator — rename, /resource-locator alias, private notes in a secured zone Oct 13, 2026
Mirrors the current Dr.Egeria command templates into templates/basic
and templates/advanced:
- Digital Product Manager: Create_Agreement, Create_Data_Sharing_Agreement
  and Create_Digital_Subscription updated.
- The Reference Data / Valid Metadata split from egeria-python odpi#450: the
  valid-metadata commands (Setup/Clear Valid Metadata Value, Map Name and
  Map Value; Set Consistent Metadata Values; Link/Detach Specification
  Property Assignment) move to a new "Valid Metadata" folder, and Reference
  Data gains the reference-data set/value and valid-value link/detach
  commands.

Source: egeria-python c338bbb0 (PR odpi#451, not yet merged), plus the
Reference Data / Valid Metadata split from PR odpi#450 (a24635d2).

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…lationship

As the Egeria team suggested: after journal-my-activity creates the
entry (and it is re-zoned), an Actions relationship is created, with the
resource as actionCause (end 1) and the JournalEntry, an Action subtype,
at end 2. journal-my-activity cannot take a cause itself (it passes none
to createNoteLogEntry), so the link is a separate Metadata Expert
related-elements call.

- The user's own journal listing now shows what each entry is about.
- A resource's private notes are read through Asset Maker's
  sponsored-actions query (the user's own JournalEntries only) instead
  of scanning the whole journal. activity_status_list=None is needed:
  pyegeria's default of IN_PROGRESS silently drops journal entries.
- If the link fails, the API returns 502 and says the note is saved and
  private but won't show on this resource.
- Verified on quickstart: linked test entry 8bec72e4 to "categories".
  Erin reads it from the resource and in her journal listing (with its
  actionCause); peterprofile and garygeeke get nothing.
- BACKLOG RL-1 records the Egeria team's acknowledged zone bug (work
  starts 2026-10-14) and this design.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
/api/rest-apis fetches the platform's OpenAPI spec with the caller's
X-Egeria-Token when there is one. When that token had expired, Egeria
answered 401 on every api-docs path and the endpoint returned 502 in
about 0.1 s, but only while the spec cache was cold (after the one-hour
TTL or an app restart), so the view failed intermittently. egeriaFetch
renews tokens only on a 401, so the page never recovered.

The spec is the platform's and the same for every user. On a 401 with
the caller's token, the fetch now retries once with a token minted from
the server's own credentials. Fetch failures are logged as warnings
(they were debug), and the 502 detail lists what each path answered.

Reproduced on quickstart: with the cache cleared, an invalid
X-Egeria-Token gave 502; after the fix it gives 200. Mirrored to
freshstart.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
…(CodeQL py/full-ssrf)

Restructuring the OpenAPI fetch for the expired-token retry moved the
requests.get that CodeQL had flagged before (alerts 17/18, dismissed as
false positives because _validate_platform_url guards it), so it was
raised again as new critical alerts 36/37.

Rather than dismiss it again, remove the flow: the request URL is now
built from the deployment's configured platform URL alone, and a
caller-supplied `url` that differs from it is refused with a 400. Nothing
legitimate is lost: the frontend never sends a custom url, the warm-up
already uses the default, and the guard already refused any other host
that resolves internally.

Verified on quickstart: default 200; an expired token on a cold cache
still 200; ?url=https://example.com returns 400 with the reason.
Mirrored to freshstart.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
Picks up odpi#630 (secret store updates for the new governance zone rule)
alongside this branch's Resource Explorer account in the quickstart
user directory.

Signed-off-by: Dan Wolfson <dan.wolfson@pdr-associates.com>
@dwolfson
dwolfson merged commit ed3374a into odpi:main Oct 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants