diff --git a/.bestpractices.json b/.bestpractices.json index 5cf7b81..38180db 100644 --- a/.bestpractices.json +++ b/.bestpractices.json @@ -68,7 +68,7 @@ "dynamic_analysis_enable_assertions_status": "Met", "dynamic_analysis_enable_assertions_justification": "Public-source evidence: the verification configuration runs deterministic varied-input SQL checks with always-enabled Check.Equal/Check.That and expected-error assertions, including exact PostgreSQL literal round trips, no unexpected truncation and second-statement/control-statement rejection: https://github.com/codegiveness/postgresql-sharp-mcp/blob/bde167e95e0fb3ff74b895db55c87f4b04d69b0c/tools/PostgreSqlMcp.Verify/FuzzChecks.cs . These assertions belong to the test verifier, not the production server, and integration succeeded in https://github.com/codegiveness/postgresql-sharp-mcp/actions/runs/36975816424 . This does not establish release-specific pre-release analysis or any branch-coverage percentage.", "know_secure_design_status": "Met", - "know_secure_design_justification": "Owner attestation: the project owner, a primary developer, attests to knowing how to design secure software, including the Saltzer and Schroeder principles this criterion lists. The repository does not prove that knowledge; it shows design choices made with it. Tool calls cross an explicit stdio trust boundary and cannot supply connection strings or change host, login or TLS settings: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#trust-boundary . Least-privilege PostgreSQL roles are the authorization authority; SQL defaults to server-owned read-only transactions and writes require explicit opt-in: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#postgresql-permissions-are-the-authority and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Core/SqlExecutor.cs#L30-L35 . An optional database lock refuses out-of-lock databases before connecting and verifies PostgreSQL grants at startup: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#database-lock-hardening . Server-owned connection settings disable error-detail and parameter logging: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Core/DatabaseRegistry.cs#L30-L36", + "know_secure_design_justification": "Owner attestation: the project owner, a primary developer, attests to knowing how to design secure software, including the Saltzer and Schroeder principles this criterion lists. The repository does not prove that knowledge; it shows design choices made with it. Tool calls cross an explicit stdio trust boundary and cannot supply connection strings or change host, login or TLS settings: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#trust-boundary . Least-privilege PostgreSQL roles are the authorization authority; SQL defaults to server-owned read-only transactions and writes require explicit opt-in: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#postgresql-permissions-are-the-authority and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Core/SqlExecutor.cs#L30-L35 . An optional database lock refuses out-of-lock databases before connecting and checks PostgreSQL grants at startup (warnings by default, a startup refusal with POSTGRES_DATABASE_LOCK_MODE=strict): https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#database-lock-hardening . Server-owned connection settings disable error-detail and parameter logging: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Core/DatabaseRegistry.cs#L30-L36", "know_common_errors_status": "Met", "know_common_errors_justification": "Owner attestation: the project owner, a primary developer, attests to knowing the common kinds of errors that lead to vulnerabilities in database-access servers, including SQL injection, missing authorization, credential and information exposure and resource exhaustion, and at least one mitigation for each. The repository does not prove that knowledge; it shows those mitigations applied. Catalog tools pass caller values as Npgsql parameters rather than SQL text: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Tools/DatabaseTools.cs#L62-L66 and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Core/SqlExecutor.cs#L75-L76 . A statement-boundary guard accepts one statement and rejects transaction/session control, while PostgreSQL permissions and read-only transactions, not the lexer, enforce access: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src/PostgreSqlMcp.Core/SqlGuard.cs and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#postgresql-permissions-are-the-authority . Errors and logs withhold PostgreSQL messages, parameters and connection strings, and results, pools and deadlines are bounded: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#credentials-and-diagnostics and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#connection-and-resource-settings . FsCheck properties against PostgreSQL and a SharpFuzz/libFuzzer campaign on the SQL guard exercise input handling: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/tools/PostgreSqlMcp.Verify/FuzzChecks.cs and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/.github/workflows/fuzzing.yml", "report_responses_status": "Met", @@ -96,13 +96,13 @@ "delivery_unsigned_status": "Met", "delivery_unsigned_justification": "Public-source evidence: the project never retrieves a cryptographic hash over HTTP. CI, build and release tooling download third-party binaries only over HTTPS and compare them with SHA-256 or SHA-512 digests committed in the repository: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/.github/workflows/secrets.yml#L23-L35 and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/.github/workflows/release.yml#L193-L202 and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/tools/PostgreSqlMcp.Fuzz/FuzzCampaign.cs#L8-L9 and https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/tools/PostgreSqlMcp.Build/Program.cs#L16-L17 . Outside bundled third-party license texts, no http:// URL appears in the repository at this revision. Release SHA256SUMS manifests are delivered with the assets over HTTPS from GitHub Releases and covered by GitHub build attestations: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/docs/security-posture.md#supply-chain-evidence . npm and NuGet also deliver packages over HTTPS.", "crypto_keylength_status": "Met", - "crypto_keylength_justification": "Public-source evidence: the application selects no key sizes and contains no cryptographic APIs: https://github.com/codegiveness/postgresql-sharp-mcp/tree/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src . Its security mechanisms are delegated. Npgsql 10.0.3 SCRAM-SHA-256 authentication uses SHA-256, HMAC-SHA-256 and PBKDF2-SHA-256 with 256-bit outputs: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.Auth.cs#L150-L284 . TLS uses .NET SslStream with EnabledSslProtocols=None and no cipher override, so the operating system's TLS policy chooses protocol versions, cipher suites and key-exchange groups: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 and https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices . Smaller key lengths can be completely disabled through that OS policy (for example the OpenSSL security level on Linux or SChannel settings on Windows); the application has no separate key-length option. Negotiated key sizes also depend on the operator's PostgreSQL server certificate and TLS settings. A profile that omits SSL Mode requires verified TLS for a non-loopback host and uses no TLS for loopback; an explicit SSL Mode is kept: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/src/PostgreSqlMcp.Core/TlsPolicy.cs . This is not a guarantee for every platform or server.", + "crypto_keylength_justification": "Public-source evidence: the application selects no key sizes and contains no cryptographic APIs: https://github.com/codegiveness/postgresql-sharp-mcp/tree/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src . Its security mechanisms are delegated. Npgsql 10.0.3 SCRAM-SHA-256 authentication uses SHA-256, HMAC-SHA-256 and PBKDF2-SHA-256 with 256-bit outputs: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.Auth.cs#L150-L284 . TLS uses .NET SslStream with EnabledSslProtocols=None and no cipher override, so the operating system's TLS policy chooses protocol versions, cipher suites and key-exchange groups: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 and https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices . Smaller key lengths can be completely disabled through that OS policy (for example the OpenSSL security level on Linux or SChannel settings on Windows); the application has no separate key-length option. Negotiated key sizes also depend on the operator's PostgreSQL server certificate and TLS settings. A profile that omits SSL Mode uses Prefer (TLS when the server offers it, certificate not verified); an explicit SSL Mode is kept: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/src/PostgreSqlMcp.Core/TlsPolicy.cs . This is not a guarantee for every platform or server.", "crypto_working_status": "Met", - "crypto_working_justification": "Public-source evidence: the application implements no algorithm or cipher mode and contains no cryptographic APIs: https://github.com/codegiveness/postgresql-sharp-mcp/tree/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src . By default Npgsql 10.0.3 authenticates with SCRAM-SHA-256, trying SCRAM-SHA-256-PLUS channel binding first over TLS, whenever the server requests SASL, as PostgreSQL 14 and later do by default: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.Auth.cs#L50-L58 . TLS uses .NET SslStream with OS-chosen protocols and cipher suites, which .NET documents as letting the OS block versions it no longer considers secure: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 and https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices . Npgsql still performs PostgreSQL's legacy MD5 challenge-response if an operator's server is configured to request it; operators can refuse it with the Require Auth connection-string setting (for example ScramSHA256): https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/NpgsqlConnectionStringBuilder.cs#L724-L731 . The role-hardening guide configures hostssl with scram-sha-256: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#hardening-the-role . A profile that omits SSL Mode uses verified TLS (VerifyFull) for a non-loopback host and no TLS for loopback; an explicit SSL Mode is the operator's choice and is kept: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/src/PostgreSqlMcp.Core/TlsPolicy.cs", + "crypto_working_justification": "Public-source evidence: the application implements no algorithm or cipher mode and contains no cryptographic APIs: https://github.com/codegiveness/postgresql-sharp-mcp/tree/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src . By default Npgsql 10.0.3 authenticates with SCRAM-SHA-256, trying SCRAM-SHA-256-PLUS channel binding first over TLS, whenever the server requests SASL, as PostgreSQL 14 and later do by default: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.Auth.cs#L50-L58 . TLS uses .NET SslStream with OS-chosen protocols and cipher suites, which .NET documents as letting the OS block versions it no longer considers secure: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 and https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices . Npgsql still performs PostgreSQL's legacy MD5 challenge-response if an operator's server is configured to request it; operators can refuse it with the Require Auth connection-string setting (for example ScramSHA256): https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/NpgsqlConnectionStringBuilder.cs#L724-L731 . The role-hardening guide configures hostssl with scram-sha-256: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#hardening-the-role . A profile that omits SSL Mode uses Prefer (TLS when the server offers it, certificate not verified, plaintext otherwise); an explicit SSL Mode is the operator's choice and is kept: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/src/PostgreSqlMcp.Core/TlsPolicy.cs", "crypto_weaknesses_status": "Met", "crypto_weaknesses_justification": "Public-source evidence: the delegated default mechanisms do not depend on SHA-1 or on CBC modes chosen by this project. SCRAM-SHA-256 uses only SHA-256-family primitives, and SCRAM channel binding hashes SHA-1- or MD5-signed server certificates with SHA-256: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.Auth.cs#L150-L284 . TLS algorithms come from the operating system's default policy through SslStream rather than an application default: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 and https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices . TLS 1.3, negotiated when the OS and the operator's PostgreSQL server support it, offers only AEAD cipher suites. Whether a legacy TLS 1.2 CBC or SHA-1 suite could be negotiated depends on that OS policy and the operator's server configuration: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/SECURITY.md#connection-and-resource-settings . Legacy MD5 authentication is covered under crypto_working.", "crypto_pfs_status": "Met", - "crypto_pfs_justification": "Public-source evidence: the only key-agreement protocol is TLS, implemented by .NET SslStream and the operating system's TLS provider with OS-selected protocols and suites: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 . Full TLS 1.3 handshakes, used when the OS and the operator's PostgreSQL server support TLS 1.3, always use ephemeral (EC)DHE key exchange and so provide forward secrecy; with TLS 1.2, forward secrecy depends on the OS policy and the server preferring ECDHE or DHE suites. A profile that omits SSL Mode requires verified TLS for a non-loopback host and uses no TLS for loopback; an explicit SSL Mode, including one that disables TLS, is the operator's choice and is kept: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/src/PostgreSqlMcp.Core/TlsPolicy.cs . The server's TLS settings are the operator's. SCRAM authentication is not a key-agreement protocol. This is not a guarantee for every deployment.", + "crypto_pfs_justification": "Public-source evidence: the only key-agreement protocol is TLS, implemented by .NET SslStream and the operating system's TLS provider with OS-selected protocols and suites: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 . Full TLS 1.3 handshakes, used when the OS and the operator's PostgreSQL server support TLS 1.3, always use ephemeral (EC)DHE key exchange and so provide forward secrecy; with TLS 1.2, forward secrecy depends on the OS policy and the server preferring ECDHE or DHE suites. A profile that omits SSL Mode uses Prefer, so TLS (and with it forward secrecy) applies only when the server offers TLS; an explicit SSL Mode, including one that disables TLS, is the operator's choice and is kept: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/src/PostgreSqlMcp.Core/TlsPolicy.cs . The server's TLS settings are the operator's. SCRAM authentication is not a key-agreement protocol. This is not a guarantee for every deployment.", "crypto_random_status": "Met", "crypto_random_justification": "Public-source evidence: the application generates no cryptographic keys or nonces itself and contains no cryptographic or random-number APIs: https://github.com/codegiveness/postgresql-sharp-mcp/tree/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/src . Npgsql 10.0.3 generates the SCRAM client nonce with System.Security.Cryptography.RandomNumberGenerator, a cryptographically secure generator: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.Auth.cs#L194-L201 . TLS session keys and nonces are generated by the operating system's TLS provider used by .NET SslStream: https://github.com/npgsql/npgsql/blob/d3768398c17877b3a916c3c4d87e8e11698991fc/src/Npgsql/Internal/NpgsqlConnector.cs#L1229-L1239 . Neither the application nor Npgsql uses System.Random for these values.", "test_most_status": "Met", @@ -128,7 +128,7 @@ "repo_distributed_status": "Met", "repo_distributed_justification": "Public-source evidence: the source repository uses git, a common distributed version control system: https://github.com/codegiveness/postgresql-sharp-mcp.git", "release_notes_status": "Met", - "release_notes_justification": "Public-source evidence: CHANGELOG gives a human-readable summary of major changes for every released version (0.1.0, 0.2.0, 0.3.1, 0.3.2, 0.3.3 and 0.4.0), including breaking changes and upgrade impact such as the 0.4.0 database-lock startup refusal; it is not raw git log output: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/CHANGELOG.md . GitHub Releases also link each release's merged pull requests and comparison: https://github.com/codegiveness/postgresql-sharp-mcp/releases", + "release_notes_justification": "Public-source evidence: CHANGELOG gives a human-readable summary of major changes for every released version (0.1.0, 0.2.0, 0.3.1, 0.3.2, 0.3.3, 0.4.0, 0.5.0, 0.6.0 and 0.7.0), including breaking changes and upgrade impact such as the 0.4.0 database-lock startup refusal and the 0.7.0 TLS and database-lock default changes with the settings that restore 0.6.0 behavior; it is not raw git log output: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/CHANGELOG.md . GitHub Releases also link each release's merged pull requests and comparison: https://github.com/codegiveness/postgresql-sharp-mcp/releases", "report_process_status": "Met", "report_process_justification": "Public-source evidence: CONTRIBUTING tells users to submit bug reports as GitHub issues with the package version, sanitized configuration, minimal reproduction, expected and actual behavior and redacted diagnostics, and routes vulnerabilities to SECURITY: https://github.com/codegiveness/postgresql-sharp-mcp/blob/fbbe5aa0c2abea5d48d58fa282d84204921c8e19/CONTRIBUTING.md#issues-pull-requests-and-reviews and https://github.com/codegiveness/postgresql-sharp-mcp/issues", "delivery_mitm_status": "Met", @@ -209,14 +209,14 @@ "crypto_algorithm_agility_justification": "The project implements no cryptography; algorithm and protocol selection is delegated to Npgsql, .NET and the operating system's TLS and to the PostgreSQL server (SCRAM-SHA-256, other methods, TLS versions and cipher suites), so operators can switch algorithms through server, OS or connection-string settings without code changes: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/docs/assurance-case.md#3-trust-boundaries and https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#connection-and-resource-settings", "crypto_credential_agility_status": "Met", "crypto_credential_agility_justification": "Credentials are never hard-coded: they come from the environment, an owner-protected targets file or CLI options, separate from other configuration, and can be replaced by restarting the server without recompiling: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/README.md#2-prepare-the-connection-environment and https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#credentials-and-diagnostics", - "crypto_used_network_status": "Met", - "crypto_used_network_justification": "Met. The server's only network protocol is the PostgreSQL connection, and by default it is encrypted: a profile without SSL Mode uses VerifyFull for every non-loopback host, so a remote server that offers no TLS is refused with tls_unavailable instead of falling back to plaintext. Unencrypted connections happen only to loopback/Unix-socket hosts or when the operator explicitly sets SSL Mode=Disable/Allow/Prefer, which is warned about on stderr for remote hosts: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#connection-and-resource-settings . These files are changed by the pull request that proposes these answers; the URLs show the described state once that change is merged to main.", + "crypto_used_network_status": "Unmet", + "crypto_used_network_justification": "Unmet since 0.7.0. The server's only network protocol is the PostgreSQL connection. TLS 1.2 or later is supported through Npgsql and .NET SslStream, but plaintext is not disabled by default: a connection string without SSL Mode gets SSL Mode=Prefer, which uses TLS when the server offers it and otherwise continues unencrypted, without the user configuring it: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/src/PostgreSqlMcp.Core/TlsPolicy.cs . This is a deliberate maintainer decision so that a plain connection string works against a PostgreSQL server without TLS. A non-loopback profile without certificate verification prints a non-blocking stderr warning, and SSL Mode=VerifyFull (or Require, VerifyCA) in the connection string removes the plaintext fallback: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/SECURITY.md#connection-and-resource-settings and https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/README.md#hardening-for-advanced-users . 0.6.0 met this criterion by defaulting non-loopback hosts to VerifyFull; the change and the settings that restore it are in https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/CHANGELOG.md .", "crypto_tls12_status": "Met", - "crypto_tls12_justification": "TLS is performed by Npgsql through .NET SslStream; the server does not restrict protocol versions and leaves negotiation to the operating system, which on supported platforms offers TLS 1.2 and later: https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices and https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#connection-and-resource-settings . Whether TLS is used at all is the operator's SSL Mode choice (see crypto_used_network).", - "crypto_certificate_verification_status": "Met", - "crypto_certificate_verification_justification": "Met. A connection profile that omits SSL Mode gets SSL Mode=VerifyFull for any non-loopback host (certificate chain and host name verified, no plaintext or unverified fallback) and Disable only for loopback and Unix sockets; this is applied to every profile at startup. An explicit unverified mode is the operator's documented opt-out and is warned about on stderr for remote hosts. The verifier's TLS scenarios against a disposable throwaway-CA PostgreSQL show that an untrusted certificate is refused with tls_verification_failed, a configured Root Certificate connects, and a trusted chain with a host-name mismatch is rejected: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#connection-and-resource-settings and https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/README.md#connection-string-quoting-and-tls . These files are changed by the pull request that proposes these answers; the URLs show the described state once that change is merged to main.", - "crypto_verification_private_status": "Met", - "crypto_verification_private_justification": "Met. Under the default (VerifyFull for non-loopback hosts) Npgsql verifies the server certificate during the TLS handshake, before the startup packet (user name) or any password is sent. The verifier's TLS scenario asserts that after a failed verification the PostgreSQL server log contains no login attempt for the configured role. Operators who explicitly set Prefer, Allow, Require or Disable opt out; that opt-out is documented and warned about for remote hosts: https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#connection-and-resource-settings . These files are changed by the pull request that proposes these answers; the URLs show the described state once that change is merged to main.", + "crypto_tls12_justification": "TLS is performed by Npgsql through .NET SslStream; the server does not restrict protocol versions and leaves negotiation to the operating system, which on supported platforms offers TLS 1.2 and later: https://learn.microsoft.com/dotnet/core/extensions/sslstream-best-practices and https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/SECURITY.md#connection-and-resource-settings . By default (SSL Mode=Prefer) TLS is used whenever the server offers it; whether TLS is required and verified is the operator's SSL Mode choice (see crypto_used_network and crypto_certificate_verification).", + "crypto_certificate_verification_status": "Unmet", + "crypto_certificate_verification_justification": "Unmet since 0.7.0. A connection string without SSL Mode gets SSL Mode=Prefer, which never verifies the server certificate or host name when TLS is used: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/src/PostgreSqlMcp.Core/TlsPolicy.cs . Verification is an explicit opt-in: SSL Mode=VerifyFull (or VerifyCA) in the connection string, or a Root Certificate without SSL Mode, which the server maps to VerifyFull. With those modes the verifier's TLS scenarios against a disposable throwaway-CA PostgreSQL show that an untrusted certificate is refused with tls_verification_failed, a configured Root Certificate connects, and a trusted chain with a host-name mismatch is rejected: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/tools/PostgreSqlMcp.Verify/TlsChecks.cs and https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/SECURITY.md#connection-and-resource-settings . A non-loopback profile without verification prints a non-blocking stderr warning. The maintainer chose this default so that a plain connection string works against servers without TLS; a verifying default would change the answer to Met.", + "crypto_verification_private_status": "Unmet", + "crypto_verification_private_justification": "Unmet since 0.7.0. Under the default SSL Mode=Prefer, Npgsql sends the startup packet (user name) and the password to a server whose certificate was not verified, or in plaintext when the server offers no TLS: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/src/PostgreSqlMcp.Core/TlsPolicy.cs . With an explicit SSL Mode=VerifyFull or VerifyCA, or a Root Certificate without SSL Mode, the certificate is verified during the TLS handshake before any credential is sent; the verifier's TLS scenario asserts that after a failed verification the PostgreSQL server log contains no login attempt for the configured role: https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/tools/PostgreSqlMcp.Verify/TlsChecks.cs and https://github.com/codegiveness/postgresql-sharp-mcp/blob/v0.7.0/SECURITY.md#connection-and-resource-settings .", "signed_releases_status": "Met", "signed_releases_justification": "Releases from v0.2.0 carry GitHub build attestations (Sigstore keyless signatures bound to the release.yml workflow identity and the exact source commit) for every archive, package, the SBOM and SHA256SUMS; since v0.5.0 the signed bundle is also published as the provenance.sigstore.json release asset (gh release view v0.5.0 listed it on 2026-10-11), and on 2026-10-11 the existing bundles of v0.3.1, v0.3.2, v0.3.3 and v0.4.0 were attached the same way after each verified with gh attestation verify against every asset of its release. No long-lived private signing key exists on the distribution sites. The documented verification process, which checks repository, signer workflow and subject digest with gh attestation verify, is in https://github.com/codegiveness/postgresql-sharp-mcp/blob/main/docs/security-posture.md#supply-chain-evidence (the release verification commands near the end of that section). v0.1.0 predates attestations.", "version_tags_signed_status": "Unmet", diff --git a/CHANGELOG.md b/CHANGELOG.md index 211c1e9..5a3f729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- OpenSSF Best Practices: re-evaluate the proposed TLS answers in `.bestpractices.json` for the 0.7.0 `SSL Mode=Prefer` default. `crypto_certificate_verification` and `crypto_verification_private` (Silver MUST) and `crypto_used_network` (Silver SHOULD, Gold MUST) change from Met to Unmet, each with the reason and what would change it. The TLS wording in four other crypto answers now describes `Prefer`, the secure-design answer describes the advisory database-lock check, and the release-notes answer covers every release through 0.7.0. [docs/security-posture.md](docs/security-posture.md) records the new counts and closes owner checklist item 11. Nothing is saved on bestpractices.dev until the owner reviews it. + ## 0.7.0 **Upgrade note (security-relevant behavior changes): two 0.6.0 defaults are loosened so that a plain connection string works.** An omitted `SSL Mode` now means `Prefer` (TLS when the server offers it, certificate never verified, plaintext otherwise) instead of `VerifyFull`, and the database lock's PostgreSQL grant check is now advisory instead of refusing startup. An attacker on the network path can read or impersonate an unverified connection, and in advisory mode PostgreSQL does not confine the login to `POSTGRES_DATABASES`, so SQL can still reach other databases where the login's privileges allow. **To restore the 0.6.0 behavior,** put `SSL Mode=VerifyFull` in the connection string (plus `Root Certificate=` for a private CA) and set `POSTGRES_DATABASE_LOCK_MODE=strict`. Run `--validate` before reconnecting; see the [README upgrade note](README.md#upgrading-an-existing-installation). diff --git a/docs/security-posture.md b/docs/security-posture.md index d20f62c..223f699 100644 --- a/docs/security-posture.md +++ b/docs/security-posture.md @@ -167,7 +167,7 @@ GitHub profile Achievements are separate from repository status badges. Useful i The public [project entry 15155](https://www.bestpractices.dev/en/projects/15155) was enrolled at 19% in progress on 2026-10-02. Its JSON API on 2026-10-10 reported **passing** (`badge_level: passing`, passing criteria 100%, silver 15%, gold 22%), last updated 2026-10-10 13:37:58 UTC after the owner saved answers. Passing is the owner's self-assessment, not an audit. -[`.bestpractices.json`](../.bestpractices.json) proposes an answer for all 67 passing criteria (62 Met, 4 N/A, 1 Unmet on a SUGGESTED criterion); it is not a certification. The first 34 proposals and the major-feature test policy reached `main` in [PR #17](https://github.com/codegiveness/postgresql-sharp-mcp/pull/17); the remaining 33 were added from evidence checked on 2026-10-10. Historical CI evidence remains specific to its named revision. The entry owner can review automation proposals using **Save (and continue) 🤖**, following the badge application's [repository proposal instructions](https://github.com/ossf/best-practices-badge/blob/main/docs/bestpractices-json.md). Review every proposed answer before saving. Neither repository publication nor CI saves answers on the badge website. +[`.bestpractices.json`](../.bestpractices.json) proposes an answer for all 67 passing criteria (63 Met and 4 N/A; the SUGGESTED `test_most` became Met when coverage measurement was added); it is not a certification. The first 34 proposals and the major-feature test policy reached `main` in [PR #17](https://github.com/codegiveness/postgresql-sharp-mcp/pull/17); the remaining 33 were added from evidence checked on 2026-10-10. Historical CI evidence remains specific to its named revision. The entry owner can review automation proposals using **Save (and continue) 🤖**, following the badge application's [repository proposal instructions](https://github.com/ossf/best-practices-badge/blob/main/docs/bestpractices-json.md). Review every proposed answer before saving. Neither repository publication nor CI saves answers on the badge website. | Evidence available | Criteria supported | |---|---| @@ -190,18 +190,21 @@ The repository was created on 2026-10-02; activity does not supply months of mai On 2026-10-11 the [project JSON](https://www.bestpractices.dev/projects/15155.json) still reported `badge_level: passing`, passing 100%, silver 15%, gold 22% and `updated_at` 2026-10-10 13:37:58 UTC, so no silver or gold answer has been saved. The criteria are listed at [silver](https://www.bestpractices.dev/en/criteria/1) and [gold](https://www.bestpractices.dev/en/criteria/2); several criteria appear at both levels and share one answer field, so a single answer applies to both. -[`.bestpractices.json`](../.bestpractices.json) now also proposes answers for 57 silver and gold criteria: 42 Met, 11 Unmet and 4 N/A. Each Met answer cites a file, a command result or a dated API observation; files added by the same pull request resolve only after it merges. The proposals are not a certification, and nothing is saved on the hosted entry until the owner reviews each answer and saves it. Not proposed, because the repository cannot establish them: +[`.bestpractices.json`](../.bestpractices.json) now also proposes answers for 57 silver and gold criteria: 39 Met, 14 Unmet and 4 N/A (three TLS criteria changed from Met to Unmet for 0.7.0, see below). Each Met answer cites a file, a command result or a dated API observation; files added by the same pull request resolve only after it merges. The proposals are not a certification, and nothing is saved on the hosted entry until the owner reviews each answer and saves it. Not proposed, because the repository cannot establish them: - `require_2FA` and `secure_2FA`: whether the maintainer's GitHub account uses two-factor authentication, and with which method, is not observable from the repository (the API returned no value for the authenticated account on 2026-10-11). GitHub began requiring 2FA from code contributors on github.com in 2023 ([GitHub announcement](https://github.blog/news-insights/product-news/raising-the-bar-for-software-security-github-2fa-begins-march-13/)), but the answer is the owner's attestation. - `security_review`: the criterion needs a human review of the security requirements and boundary. [docs/assurance-case.md](assurance-case.md#review-record) is a draft by an AI agent and has a pending maintainer row; record the review there first. -Silver still fails on one MUST criterion, `access_continuity`, so `achieve_silver` and the Scorecard CII-Best-Practices score stay at passing until it changes and the owner saves the answers. Four other Silver MUST criteria were Unmet earlier on 2026-10-11 and are proposed as Met by engineering changes in the same pull request: `build_repeatable` (deterministic `.nupkg` and SBOM), `test_statement_coverage80` (coverlet measurement: 89.41% statements, 84.84% branches, CI gate at 80%), and `crypto_certificate_verification` and `crypto_verification_private` (written while 0.6.0 verified TLS by default; 0.7.0 no longer does, see checklist item 11). Gold additionally needs the Unmet criteria in the next table. The silver and gold answers describe 2026-10-11 and must be re-evaluated when reports, releases or settings change. +Silver fails on three MUST criteria: `access_continuity`, and since 0.7.0 `crypto_certificate_verification` and `crypto_verification_private`. So `achieve_silver` and the Scorecard CII-Best-Practices score stay at passing until they change and the owner saves the answers. Two other Silver MUST criteria were Unmet earlier on 2026-10-11 and are proposed as Met by engineering changes: `build_repeatable` (deterministic `.nupkg` and SBOM) and `test_statement_coverage80` (coverlet measurement: 89.41% statements, 84.84% branches, CI gate at 80%). Gold additionally needs the Unmet criteria in the next table. The silver and gold answers describe 2026-10-11 and must be re-evaluated when reports, releases or settings change. #### What stays unmet and what would change it | Criterion or check | Level | Why it is unmet today | Exactly what would change it | |---|---|---|---| | `access_continuity` | Silver MUST | One account holds repository admin, npm and NuGet authority, and nobody else can use it | Either a second person with admin, npm maintainer and NuGet ownership who can merge, release and publish within a week, plus a recorded handover test; or, for a single maintainer as the criterion allows, a named trusted person holding sealed recovery material for the GitHub, npm and NuGet accounts with written authority to use it, recorded and checked yearly ([GOVERNANCE.md](../GOVERNANCE.md#what-would-change-the-status)) | +| `crypto_certificate_verification` | Silver MUST | Since 0.7.0 a connection string without `SSL Mode` gets `Prefer`, which never verifies the server certificate; verification needs an explicit `SSL Mode=VerifyFull`/`VerifyCA` (or a `Root Certificate` without `SSL Mode`). This is the maintainer's beginner-default decision | A verifying default for connection strings without `SSL Mode`, which reverses that decision and again refuses servers without TLS unless the user opts out | +| `crypto_verification_private` | Silver MUST | Under the `Prefer` default the user name and password reach a server whose certificate was not verified, or travel in plaintext when the server offers no TLS | The same verifying default; with explicit `VerifyFull` the verifier already shows no login reaches the server before verification | +| `crypto_used_network` | Silver SHOULD, Gold MUST | The `Prefer` default continues in plaintext when the server offers no TLS, so an insecure connection is enabled without the user configuring it | A default that requires TLS (`Require` or a verifying mode), with plaintext only through an explicit `SSL Mode=Disable`/`Allow`/`Prefer` | | `bus_factor` | Silver SHOULD, Gold MUST | One human contributor (58 commits and Dependabot's 3 on 2026-10-11) | At least two people who can each maintain the project, which the same second maintainer provides | | `contributors_unassociated`; Scorecard Contributors | Gold MUST; check | No second contributor | At least two significant contributors not paid by the same organization; Scorecard also needs people from other organizations (three organizations scores 10) | | `two_person_review`; Scorecard Code-Review | Gold MUST; check | Every human change is authored by the maintainer and GitHub blocks self-approval; Scorecard found 0 of 27 changesets approved | A different human reviewing and approving at least half of proposed modifications, or the maintainer approving outside contributors' PRs. Bot or agent approvals do not count | @@ -219,7 +222,7 @@ Silver still fails on one MUST criterion, `access_continuity`, so `achieve_silve ### Owner action checklist -Each item changes a remote setting or a published release, or needs the owner personally. Items 1, 4, 5, 6, 7 and 10 were carried out or checked on 2026-10-11 by an AI coding agent under the maintainer's explicit authorization for that task; the results are recorded in each item. Items 2, 3, 8, 9 and 11 need the maintainer personally and are still open. +Each item changes a remote setting or a published release, or needs the owner personally. Items 1, 4, 5, 6, 7, 10 and 11 were carried out or checked on 2026-10-11 by an AI coding agent under the maintainer's explicit authorization for that task; the results are recorded in each item. Items 2, 3, 8 and 9 need the maintainer personally and are still open. 1. **Done 2026-10-11: merged** as [#67](https://github.com/codegiveness/postgresql-sharp-mcp/pull/67) after an agent review, with every hosted check green. That merge is not the maintainer's review of the drafts; item 2 remains. 2. **Read `docs/assurance-case.md` and record your review** in its review record. Confirm or correct the roadmap and governance statements, which are drafts written for the maintainer's approval. @@ -242,7 +245,7 @@ Each item changes a remote setting or a published release, or needs the owner pe 8. **Set up access continuity.** Route 2 in [GOVERNANCE.md](../GOVERNANCE.md#what-would-change-the-status) needs no second maintainer. Give a named trusted person sealed recovery material for the GitHub, npm and NuGet accounts and written authority to use it, then record the date in GOVERNANCE.md and change `access_continuity` to Met with that evidence. Never put the material in the repository. Optionally also set a GitHub account successor. 9. **Optional: recruit a second maintainer** (route 1). This is the only path to `bus_factor`, `two_person_review`, Code-Review, Contributors and a higher Branch-Protection score. No artificial reviews or contributors are used. 10. **Check the settings you own.** Read on 2026-10-11 through `gh api repos/codegiveness/postgresql-sharp-mcp --jq .security_and_analysis`, without changing anything: secret scanning enabled, push protection enabled, Dependabot security updates enabled, non-provider (generic) patterns **disabled**, validity checks **disabled**; the open secret-scanning alert count was 0. Enabling generic patterns and validity checks is a settings change for the owner. -11. **After 0.7.0 is released, re-evaluate the TLS answers before saving them.** The default is now `SSL Mode=Prefer` (TLS when the server offers it, certificate never verified, possible plaintext fallback); verification needs an explicit `SSL Mode=VerifyFull` in the connection string. The proposed answers in [`.bestpractices.json`](../.bestpractices.json) for `crypto_used_network`, `crypto_certificate_verification` and `crypto_verification_private`, and the TLS sentences in the `crypto_keylength`, `crypto_working` and `crypto_pfs` justifications, were written while 0.6.0 verified TLS by default and no longer describe the default. Re-evaluate each of them, and change or withdraw any Met answer that no longer holds, before saving them on bestpractices.dev. `.bestpractices.json` has not been edited for this release; the owner decides. +11. **Done 2026-10-11: TLS answers re-evaluated for 0.7.0** at the maintainer's request. 0.7.0's default is `SSL Mode=Prefer` (TLS when the server offers it, certificate never verified, possible plaintext fallback). In [`.bestpractices.json`](../.bestpractices.json), `crypto_used_network`, `crypto_certificate_verification` and `crypto_verification_private` changed from Met to Unmet, with the reason and what would change them (see the table above). The TLS sentences in `crypto_tls12`, `crypto_keylength`, `crypto_working` and `crypto_pfs` now describe the `Prefer` default. `know_secure_design` now says the database-lock grant check warns by default and refuses only in strict mode, and `release_notes` lists every release through 0.7.0. The cited files point at the `v0.7.0` tag. Saving the answers on bestpractices.dev remains item 3. ## Sources