This is an automated email from the ASF dual-hosted git repository.

FreeAndNil pushed a commit to branch Feature/security-audit-hardening
in repository https://gitbox.apache.org/repos/asf/logging-log4net.git


The following commit(s) were added to 
refs/heads/Feature/security-audit-hardening by this push:
     new dc17e1ba document the conventions the security scan work relied on #309
dc17e1ba is described below

commit dc17e1ba381460a6fd0eb0ac0660922e89350e7a
Author: Jan Friedrich <[email protected]>
AuthorDate: Tue Aug 18 00:49:40 2026 +0200

    document the conventions the security scan work relied on #309
---
 AGENTS.md | 24 +++++++++++++++--
 CLAUDE.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 103 insertions(+), 13 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 97ef271b..d6f9eec5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -10,7 +10,7 @@ This is mandatory: skipping steps leads to duplicate reports 
and wasted time for
 ### Step 1: Read the security model
 
 Fetch and read the project's security model before evaluating any finding:
-https://raw.githubusercontent.com/apache/logging-site/refs/heads/main-site-pro/src/site/antora/modules/ROOT/pages/_threat-model-common.adoc
+https://raw.githubusercontent.com/apache/logging-site/refs/heads/main/src/site/antora/modules/ROOT/pages/_threat-model-common.adoc
 
 Use this to answer:
 - Is this component/behavior in scope at all?
@@ -18,6 +18,21 @@ Use this to answer:
 
 If the finding is out of scope per the model, **stop here** and inform the 
researcher.
 
+Two rules from the model account for most of what gets reported wrongly. Read 
the model itself
+rather than relying on this summary, but know them before you start:
+
+- **Configuration is operator-supplied and trusted**, including configuration 
URIs and the types,
+  members and converters that configuration names. A finding that needs the 
attacker to control
+  configuration, a watched configuration file, or the format string of a log 
statement is out of
+  scope: that is application misuse. Protecting those resources, and 
transmitting them over a
+  confidential channel, is a deployer responsibility the model states 
explicitly.
+- **Content is untrusted and must never be rejected**, because rejecting it 
would turn a malicious
+  value into a denial of service, so it has to be escaped or sanitized 
instead. Structural
+  identifiers, such as logger names or the identifier fields of a structured 
log message, are
+  trusted, and there the model allows *rejecting* a malformed value rather 
than silently altering
+  it. Getting these two the wrong way round produces a plausible-looking 
report that proposes
+  exactly the wrong fix.
+
 ### Step 2: Check previously disclosed vulnerabilities
 
 Read the project's Vulnerability Disclosure Report to check for duplicates:
@@ -29,7 +44,7 @@ If it overlaps with a known issue, **stop here**, link to the 
existing advisory
 ### Step 3: Read the Security FAQ
 
 Read the Security FAQ before concluding anything is a vulnerability:
-https://raw.githubusercontent.com/apache/logging-site/refs/heads/main-site-pro/src/site/antora/modules/ROOT/pages/security/faq.adoc
+https://raw.githubusercontent.com/apache/logging-site/refs/heads/main/src/site/antora/modules/ROOT/pages/security/faq.adoc
 
 The FAQ lists behaviors that are **intentional and not vulnerabilities**.
 If the finding matches an FAQ entry, inform the researcher that it is a known 
non-issue
@@ -52,6 +67,11 @@ Assess the finding:
 
 ## Report quality rules
 
+- **Only call something a vulnerability when it really is one.** Name the 
adversary, then check that
+  capability against the model. If it needs a misconfiguration, a co-resident 
local user, or
+  anything the model does not grant, it is a correctness bug, a reliability 
defect or hardening, and
+  saying so is more useful than a severity. Do not inherit the framing of a 
scanner report that
+  arrived with severities already attached.
 - Never speculate about impact beyond what you can demonstrate.
 - Reproduction steps must be minimal and self-contained.
 - Do not include unrelated findings in the same report: one issue per report.
diff --git a/CLAUDE.md b/CLAUDE.md
index 94d7f463..1aa100c9 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -26,33 +26,33 @@ almost always be doing.
   (238 of 244 files in `src/log4net`). Copy it verbatim into new files.
 - File-scoped namespaces (`namespace log4net.Appender;`). Note `.editorconfig` 
still says
   `csharp_style_namespace_declarations = block_scoped:silent`, but 242 of 244 
files are
-  file-scoped — follow the code, not that setting.
+  file-scoped: follow the code, not that setting.
 - `using` directives outside the namespace, in one contiguous block.
 
 ### Language usage
-- **Explicit types, not `var`** — all three `csharp_style_var_*` options are 
`false`.
+- **Explicit types, not `var`**: all three `csharp_style_var_*` options are 
`false`.
   Write `StringWriter writer = new(...)`.
 - Target-typed `new()` and collection expressions (`private static readonly 
char[] _x = [',', ';'];`).
-  Omit the type wherever the target is known — including `return new(…);` and 
`=> new(…);`, where
+  Omit the type wherever the target is known, including `return new(…);` and 
`=> new(…);`, where
   the enclosing member's return type supplies it. It cannot be omitted when 
the target type is an
   interface or abstract class, as in `Func<ISmtpTransport> f = () => new 
MailKitSmtpTransport();`.
-- Expression-bodied members whenever the body fits on one line — this includes 
constructors
+- Expression-bodied members whenever the body fits on one line, including 
constructors
   (`resharper_constructor_or_destructor_body = expression_body`).
 - Braces on `if`/`else` bodies even for a single statement.
 - `LangVersion` is `latest`, and current C# features are welcome and in use: 
primary
   constructors (`csharp_style_prefer_primary_constructors = true`), the 
`field` keyword in
   property accessors, list patterns, `switch` expressions.
 - **Wrap long string literals with a multi-line raw string (`"""`), never with 
`+`
-  concatenation.** This includes attribute arguments — see the 
`[Obsolete(...)]` message on
+  concatenation.** This includes attribute arguments; see the 
`[Obsolete(...)]` message on
   `log4net.Appender.SmtpAppender`. Raw strings have no line-continuation, so 
each source line
   break really is a `\n` in the value, but that is fine here: compiler 
diagnostics render those
   newlines as spaces, so a wrapped message still reads as one sentence. Raw 
strings are constant
-  expressions, so they are legal in attributes, and the feature is purely 
syntactic — it works on
+  expressions, so they are legal in attributes, and the feature is purely 
syntactic, so it works on
   `net462`/`netstandard2.0` too.
 - Private fields are `_camelCase`. Private fields and helper methods are 
commonly placed
   *after* the public surface of the type rather than at the top.
 
-### Nullability — the big constraint
+### Nullability, the big constraint
 - `Nullable` is enabled solution-wide with `WarningsAsErrors=nullable`: **any 
nullability
   warning is a build error**, so it cannot be deferred.
 - `log4net` targets `net462;netstandard2.0`. **Neither reference assembly is 
nullable-annotated**,
@@ -68,7 +68,7 @@ almost always be doing.
 - Use the internal `log4net.Util.Log4NetAssert` extensions rather than 
hand-rolled checks:
   `EnsureNotNull()`, `EnsureNotNullOrEmpty()`, `EnsureIs<T>()`. They carry
   `[CallerArgumentExpression(nameof(value))]`, so no argument name is passed 
at the call site.
-  This includes constructor and property assignments — write `_x = 
x.EnsureNotNull();`,
+  This includes constructor and property assignments: write `_x = 
x.EnsureNotNull();`,
   not `_x = x ?? throw new ArgumentNullException(nameof(x));`.
 - Appenders never let exceptions escape to the caller. The house pattern is
   `catch (Exception e) when (!e.IsFatal()) { ErrorHandler.Error("...", e); }`.
@@ -83,13 +83,44 @@ almost always be doing.
   requires linking `NotNullAttribute`, `ValidatedNotNullAttribute` and
   `CallerArgumentExpressionAttribute`, or you get `CS0122`.
 - Analyzers (`Microsoft.CodeAnalysis.NetAnalyzers`, `AnalysisLevel 8`, 
`src/log4net.globalconfig`)
-  run on every build. **The solution builds with 0 warnings — keep it that 
way.**
+  run on every build. **The solution builds with 0 warnings, keep it that 
way.**
+
+### Documentation comments
+- **Every public and protected member gets an XML doc comment**, in test code 
as well as production
+  code: test methods, nested helper classes and hand-written fakes included.
+- Use `/// <inheritdoc/>` when the member implements an interface or overrides 
a base member, and a
+  real `<summary>` for everything else. `Log4NetTransaction` in the AdoNet 
test doubles is the
+  pattern to copy.
+- When checking whether a member is documented, remember that `[Test]`, 
`#pragma` and
+  `// ReSharper disable` lines legitimately sit between the doc comment and 
the declaration.
+
+### Writing, in code and everywhere else
+- **Never use an em dash (`—`) or en dash (`–`).** Use a plain hyphen, or 
restructure with a colon,
+  comma or parentheses. This covers comments, XML docs, commit messages, 
AsciiDoc and chat.
+- In AsciiDoc, ` -- ` is also forbidden: Asciidoctor renders a spaced double 
hyphen as an em dash,
+  so it breaks the rule even though the source looks like plain hyphens. Grep 
touched files for
+  `[—–]` and ` -- ` before presenting a change.
+- No underscores in identifiers, including test method names. 
`AllContainsEveryFlag`, not
+  `All_ShouldContainAllFlags`. (Private fields are `_camelCase`, which is the 
one exception.)
 
 ### Tests
 - NUnit 4, not MSTest, and always the constraint model: `Assert.That(actual, 
Is.EqualTo(expected))`
   (810 uses of `Assert.That`, zero of `Assert.AreEqual`). `[TestFixture]`, 
`[Test]`, `[TestCase]`,
   with `[SetUp]`/`[TearDown]` for per-test state.
-- `NUnit.Analyzers` warnings are errors too — e.g. NUnit1032 requires an 
`IDisposable` fixture
+- Use an expression body for a single-statement test: `public void X() => 
Assert.That(...);`.
+- **`log4net` has no `InternalsVisibleTo`**, so private and internal members 
are exercised through
+  reflection, not by widening their accessibility. See `SystemInfoTest`, 
`LevelMappingTest` and
+  `UserNameFixingTest` for the `BindingFlags.Static | BindingFlags.NonPublic` 
pattern.
+  `log4net.Ext.Mail` does grant `InternalsVisibleTo` to its own test project.
+- Mark a test `[NonParallelizable]` when it mutates static state 
(`LogLog.InternalDebugging`, a
+  static field on a test double, a process-wide native registration).
+- Wrap expected internal logging in 
`LogLog.ExecuteWithoutEmittingInternalMessages(...)` and capture
+  it with `LogLog.LogReceivedAdapter` rather than letting it reach the 
console. Appender errors are
+  emitted by default, so a test that provokes one will otherwise add noise to 
the suite output.
+- Guard platform-specific tests with `[Platform("Win")]` / 
`[Platform("Linux")]`. A test that only
+  runs on Windows leaves the behaviour unverified in local Linux runs, so 
prefer a cross-platform
+  home for the assertion when one exists.
+- `NUnit.Analyzers` warnings are errors too: for example NUnit1032 requires an 
`IDisposable` fixture
   field to be disposed in a `[TearDown]` method.
 - For code that talks to the outside world, introduce a narrow interface and 
hand-write a fake;
   there is no mocking library in any test project. See `ISmtpTransport` / 
`FakeSmtpTransport`.
@@ -97,6 +128,45 @@ almost always be doing.
   `dotnet test src/<project>.Tests/<project>.Tests.csproj`.
 - **When inspecting build output, redirect it to a file and read the whole 
thing; do not pipe
   MSBuild through line-oriented tools.** `grep`/`Select-String` cannot match 
across newlines, and
-  MSBuild's console logger formats differently when piped than when redirected 
— a multi-line
+  MSBuild's console logger formats differently when piped than when 
redirected, so a multi-line
   diagnostic message then looks truncated when it is not. Before reporting 
that the toolchain
   mangles something, re-check with `dotnet build … > out.txt 2>&1` and inspect 
`out.txt`.
+
+## Changelog
+
+Every user-visible change gets an entry in `src/changelog/<unreleased 
version>/`, named
+`<issue>-<kebab-case-slug>.xml`. The format is the log4j changelog schema:
+
+- `type` is one of `added`, `changed`, `fixed`, `removed`, `updated`.
+- **Every `<issue>` element requires both `id` and `link`**; the export fails 
with
+  `missing attribute: link` otherwise, which is only caught by the Maven site 
build.
+- Put anything that has no issue number, such as an external finding 
identifier, in the description
+  text rather than inventing an `<issue>` for it.
+- `src/changelog/3.3.2/298-fix-interprocesslock-mutex-leak.xml` shows the 
shape for a change that
+  came out of an external audit.
+
+## Documentation site
+
+The manual lives in `src/site/antora/modules/ROOT/pages/`. A new appender page 
needs three edits,
+not one: the page itself, an `xref` line in `nav.adoc` (kept alphabetical), 
and the appender table
+in `manual/configuration/appenders.adoc`.
+
+## Security findings
+
+**[AGENTS.md](AGENTS.md) decides whether something is in scope and whether it 
is a vulnerability.**
+Read it before triaging a report, and describe a finding in commit messages 
and changelog entries
+the way it comes out of that assessment: a correctness bug, a reliability 
defect or hardening is
+none the worse for being called one.
+
+What that leaves for this file is where the answers live in the code:
+
+- When a report is likely to recur on a path the threat model already settles, 
leave a short comment
+  at the site with a link to the model rather than changing the code. 
`XmlConfigurator` and
+  `XmlHierarchyConfigurator` carry these for the configuration-is-trusted 
paths, and
+  `SystemStringFormat` for the format string.
+- `LocalSyslogAppender.EscapeNulCharacters` and 
`RemoteSyslogAppender.ValidateIdentity` are the two
+  sides of the content and structural-identifier rule: content is escaped and 
never rejected, a
+  malformed identifier is reported rather than quietly repaired.
+- Deliberate secure-default choices belong in the changelog with their opt-out 
named, so that an
+  upgrade surprise is searchable. See the entries for `SendTimeoutMillis`, 
`MatchTimeoutMillis` and
+  `LockTimeoutMillis`.

Reply via email to