Files
Libation/docs/development/contribute.md
T
Cursor Agentandrmcrackan 742e58d2e8 Mask the account on the paths that do not go through an exception
Account.ToString() returned "id - locale", so interpolating an account or
logging a non-destructured {Account} published the address. It now returns
the masked entry, with a DebuggerDisplay keeping the real values visible
while debugging. Nothing in the UI relied on it: both scan dialogs build
their own labels.

For structured logging, an ILogMasked type is reduced to its masked entry
by a destructuring policy, which covers the {@DebugInfo} shape most of
Libation's logging uses. And DecryptKey - the activation bytes - is now a
SecretString, so it has no plaintext for a reflective dump to find at all.
Its JSON stays the bare string it always was, so existing settings files
load unchanged.

A registered policy that nobody notices is missing protects nothing, so
the tests write through a logger built by ConfigureLogging itself rather
than a hand-made one. Deleting either registration fails them: the masked
object comes out whole, and a destructured secret renders as
{"HasValue":true} instead of its length.

The contribute guide now states the rule, since the reason for all of
this is invisible from the code alone: log files get attached to public
issues, so treat what goes in them as published.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-17 02:04:09 +00:00

46 lines
2.3 KiB
Markdown

# Contribute to Libation
We welcome contributions! Whether it's fixing bugs, adding features, or improving documentation, your help is appreciated.
> [!WARNING]
> Read the [Development - Getting Started](/docs/development/getting-started) guide first.
## Getting Started
1. **Fork the repository** on GitHub.
2. **Clone your fork** locally.
3. **Create a branch** for your feature or fix:
```bash
git checkout -b feature/my-new-feature
```
## Code Style
- Follow standard C# coding conventions.
- Ensure your code builds and runs without errors.
- Clean up any unused dependencies or imports.
## Logging and secrets
We ask people to attach `Log.log` to public issue reports, so treat everything written there as published.
- Log `account.MaskedLogEntry`, never an account's id or name. `AccountCredentialStatus.FormatAccountLabel` gives the unmasked label and is for dialogs shown to the account's owner only.
- Never hang an `Account`, an `Identity`, or anything holding one off an exception. Serilog.Exceptions reflects over every public property of a logged exception and follows nested objects, so a live account on an exception publishes its address and activation bytes no matter what `ToString` says. Carry an `AccountSummary` instead. A test enforces this: see `ExceptionsCannotReachAnAccount`.
- Remember that an exception's `Message` gets logged too, so mask anything you interpolate into one.
- Wrap a new secret in `Dinah.Core.Security.SecretString`, which keeps the value behind `Reveal()` where reflection cannot find it and prints `[REDACTED length=N]` everywhere else. Implement `ILogMasked` on a type that needs a masked identity in logs.
- `Reveal()` at the point of use, and nowhere else. Interpolating a secret into a string is not a compile error, so a redaction can end up sent over the wire in place of the real value - cover any new call site with a test.
## Submitting a Pull Request
1. **Commit your changes** with a clear message.
2. **Push to your fork**:
```bash
git push origin feature/my-new-feature
```
3. **Open a Pull Request** on the main repository.
4. Describe your changes and link any related issues.
## Reporting Issues
If you find a bug or have a feature request, please [open an issue](https://github.com/rmcrackan/Libation/issues) on GitHub.