Skip to content

feat(client)!: read credentials from a user-scoped file - #194

Merged
willkg merged 7 commits into
mainfrom
credentials-file
Sep 23, 2026
Merged

willkg merged 7 commits into
mainfrom
credentials-file

Conversation

@willkg

@willkg willkg commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

This replaces .env file support with a user-scoped credentials file. This also removes --url, --username, and --cloud-id flags. These changes reduce the complexity around finding .env files, providing credentials, and a plethora of confusing edge cases. No one wants confusing edge cases with credentials.

The plan is _plans/050_credentials-file.md, and the reference for users is the new docs/credentials.md.

What changes

  • Each setting resolves key by key from, highest first: the file named by --env-file, the CONFLUENCE_* environment variables, and ~/.config/markfluence/credentials (or $XDG_CONFIG_HOME/markfluence/credentials when that is absolute), on Linux and macOS alike.
  • .env is no longer discovered by walking up from the working directory, so a cloned checkout cannot supply a URL to send your token to.
  • The URL and the token must come from the same source, or the command fails naming both.
  • The cloud ID is read only from the URL's source. One ignored from a place above the URL's (for example an exported CONFLUENCE_CLOUD_ID with the URL in the credentials file) earns a warning.
  • The credentials file is read only when a higher source leaves a setting unset. A missing one is fine; one that exists but cannot be read, including a dangling symlink, is an error.
  • The missing-settings and same-source errors link to docs/credentials.md.
  • The permission warning (warn when .env holding the API token is readable by others #136) covers the credentials file, and judges only regular files, so --env-file <(pass show …) does not warn.

Side effects: --root no longer affects credentials; create, update, and attachment-upload no longer report the working directory's root in root: or roots; and a malformed markfluence.yaml above the working directory no longer fails commands that never read it, such as read 123 and search.

Tests run with HOME and XDG_CONFIG_HOME pointed at an empty directory and CONFLUENCE_* unset, through a new internal/testenv that every package whose code calls Resolve uses from TestMain, so a developer's real credentials cannot reach a test.

Breaking

A project .env is no longer read, and the three flags are removed. Move credentials to ~/.config/markfluence/credentials, or name the file with --env-file. The GitHub Action and markfluence-demo pass all four settings as environment variables and need no change.

A command that writes the credentials file is #193.

Fixes #188

Plans #188: a user-scoped credentials file replaces .env discovery,
and the --url, --username, and --cloud-id flags go away.
Every package whose tests reach client.Resolve now runs them with HOME
and XDG_CONFIG_HOME pointing at an empty temporary directory and the
CONFLUENCE_* variables unset. Changes no behaviour today; it makes #188's
user-scoped credentials file invisible to tests, which would otherwise
fill in settings a test left unset.

It is done in TestMain rather than per test so a test added later cannot
forget it.
Credentials now come only from sources the user chose (#188), highest
first: the file named by --env-file, the CONFLUENCE_* environment
variables, and a credentials file at
$XDG_CONFIG_HOME/markfluence/credentials, else
$HOME/.config/markfluence/credentials.

- .env is no longer discovered by walking up from the working
  directory, so a checkout cannot supply credentials.
- The --url, --username, and --cloud-id flags are gone.
- The URL and the token must come from the same source, or the
  command fails naming both.
- The cloud ID is read only from the URL's source.
- The credentials file is read only when a higher source leaves a
  setting unset; a missing one is fine, an unreadable one is an error.

Resolve now takes only the env-file path. Nothing discovers a root from
the working directory any more, so --root no longer affects credentials,
and a malformed markfluence.yaml no longer fails commands that never
read it.

BREAKING CHANGE: a project .env is no longer read, and the --url,
--username, and --cloud-id flags are removed. Move credentials to
~/.config/markfluence/credentials or name the file with --env-file.
The README's Configure section, CONTRIBUTING, SECURITY, .env.example,
docs/root-model.md, docs/json-output.md, the schema's warnings
descriptions, docs/confluence/, the internal/project and internal/jsonout
comments, and CLAUDE.md now describe #188's credential sources: an
--env-file, the environment, and ~/.config/markfluence/credentials, with
no credential flags and nothing discovered from a project.
- CLAUDE.md no longer says the cloud ID may be a flag.
- The help and README say XDG_CONFIG_HOME counts only when absolute.
- The missing-settings error says "set it in" for one setting, and
  the unreadable-credentials error shows the path as ~/... like the
  others.
- Tests: the malformed-project-file test no longer goes through
  --env-file (which skipped discovery before #188 too); the ~ form is
  pinned against a real home directory; a credentials-file cloud ID is
  ignored when the URL comes from the environment; a complete run does
  not read, and so cannot fail on, an unreadable credentials file; and
  the no-home error offers only the places that exist.
The missing-settings and same-source errors now end with a link to
docs/credentials.md on GitHub, the one reference for credentials:
where markfluence looks, how to set up the credentials file, the two
rules that protect the token, using another site for one command, the
permission warning, and what each error means.

The README's Configure section keeps the setup steps and points there,
and the root --help summarises and links to it. The plan's D8 records
the link, and that markfluence does nothing about an existing .env.
- A CONFLUENCE_CLOUD_ID ignored from a place above the URL's now warns:
  that is someone who exported it with the URL in the credentials file,
  and would otherwise get an unexplained 401. One below the URL's place
  (a credentials file for another instance) stays quiet. The README's
  scoped-token section says to set it where the URL is.
- The permission warning judges only regular files, so
  --env-file <(pass show ...) no longer suggests an impossible chmod.
- When only one of the URL and the token is set, the "missing" error
  offers only its place, since anywhere else fails the same-source rule.
- A dangling symbolic link at the credentials path is an error, not
  "no credentials file".
- Test isolation moves to a new internal/testenv, used by internal/client
  too instead of a copy, and by every package whose code calls Resolve.
- docs/credentials.md's sample error matches the real one, and the
  warnings descriptions name both credential warnings.
@willkg
willkg merged commit ef434a9 into main Sep 23, 2026
1 check passed
@willkg
willkg deleted the credentials-file branch September 23, 2026 17:36
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.

Replace .env discovery and the credential flags with a user-scoped credentials file

1 participant