Skip to content

Guarantee published and exported projects never carry credentials #1680

Description

@giswqs

Summary

Guarantee that a published or exported project never carries a credential, by centralizing the redaction and adding a test per egress path that asserts it.

Why

A .geolibre.json can plausibly reach places a secret should not: share.geolibre.app (public or unlisted, so a URL anyone can fetch), a standalone HTML export, a project handed to a colleague as a file, a Jupyter notebook committed to a repository.

Meanwhile the app holds a growing set of credentials that are conceptually attached to layers: custom request headers for authenticated 3D Tiles, PostGIS connection strings, geocoding apiKeys in the project preferences, Cesium ion and Google Maps tokens, and whatever an external plugin decides to persist in its own layer or plugin state.

The publish path in useProjectFileActions.ts already does careful work here — it rewrites the project on the way out, and there is precedent for deliberately not stamping shares with information that turned out to disclose too much. But the protection is currently a property of the code paths that happen to exist rather than an invariant the codebase enforces. A new layer type, a new plugin storing an auth header in its state, or a new export path can quietly break it, and nothing fails.

The failure is also silent and delayed: an unlisted project with a key in it will work perfectly and disclose the key for as long as it exists.

Proposal

1. Mark credential-bearing fields once

Identify, in packages/core, every field in the project schema that may hold a secret — request headers, connection strings, apiKeys, plugin-state fields declared as sensitive — and mark them in one place rather than by name at each call site.

2. One redaction helper, used by every egress

A single redactCredentials(project) applied by: the share upload, Save/Save As (with a prompt — a local save may legitimately want to keep a connection string, and the user should choose knowingly), the standalone HTML export, @geolibre/embed payloads, the collaboration snapshot pushed to the relay, and the Python widget's project serialization.

The collaboration path deserves emphasis: a snapshot goes to a relay and is fanned out to every participant, including view-only guests. Anything sensitive in the project state is disclosed to everyone in the session today.

3. Tests as the actual deliverable

The mechanism is easy; keeping it true is the point. Add a test per egress path that builds a project containing a marked credential in every marked field and asserts the serialized output contains none of them. Add a schema-level test that fails when a new field is added to a credential-bearing type without an explicit sensitive/not-sensitive decision, so the next such field cannot be added silently.

4. Tell the user what happened

When redaction removes something, say so at the point of sharing: "the token for this 3D Tiles layer was not included — recipients will need their own, or use a brokered credential." Silent removal turns into a bug report about a broken layer.

Scope notes

  • Plugin state is the hardest part. External plugins can persist arbitrary state; the plugin API should let a plugin declare fields as sensitive (docs/plugin-api.md), and unknown plugin state should be handled by a documented, conservative default.
  • Coordinate with the credential-broker issue: a brokered reference is not a secret and should survive redaction, which is what makes brokering the working answer for shared maps.
  • Verify the current behavior first and write it down. Part of the value here is a documented invariant in docs/project-format.md where today there is an assumption.

Effort

Small to medium, and high value for the size — mostly tests and one helper.


Part of #1665 (access control umbrella).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancement (small)Minor feature, small UI tweak, or text adjustment

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions