core/provenance.py
Rama main · réplica de lectura del repositorio original.
# SPDX-License-Identifier: BUSL-1.1
# Copyright (c) 2024-2026 Ali Sadeghi Aghili
"""Identity, licence, and provenance of this software, stated at run time.
Why this module exists
----------------------
A licence in a file is only read by someone who goes looking for it. This
module puts the same statement where it is seen at the moment it matters:
in the log of whoever is running the software, on every start-up.
That serves two ends, and it is worth being honest that neither is a
technical barrier -- anyone determined to strip this out can:
1. **Nobody can run this and later claim they did not know the terms.**
Under most copyright regimes the difference between an innocent and a
knowing infringement changes the outcome, and a start-up banner in the
operator's own logs is unusually hard to argue around.
2. **The operator learns the terms without having to care about
licensing.** Most people running a copy of somebody else's project are
not adversaries; they inherited it from a colleague and never saw a
LICENSE file. One line in the log tells them.
What this module deliberately does NOT do
-----------------------------------------
It does not refuse to start, degrade, or phone home when the licence
files are missing. A kill switch keyed on the presence of a file is a
production outage waiting for the day someone builds a container image
that excludes ``*.md``, and the person it would hurt is whoever is on
call -- usually a licensee, not an infringer. It warns loudly instead.
It also contains nothing hidden: no invisible characters, no text
designed to make an automated reader misbehave. Everything here is meant
to be read. A concealed marker discovered later turns a clean provenance
argument into an argument about the concealment.
Provenance
----------
:data:`FINGERPRINT` is a fixed, arbitrary constant carried by this
codebase and by nothing else. It is documented rather than hidden, which
costs nothing: its evidential value comes from being *present* in a
derivative work, not from whoever copied it failing to notice. Two
codebases sharing this string share an origin.
Examples
--------
>>> LICENSOR
'Ali Sadeghi Aghili'
>>> LICENCE_ID
'BUSL-1.1'
>>> "Ali Sadeghi Aghili" in banner()
True
>>> "BUSL-1.1" in banner()
True
>>> banner(ascii_only=True).isascii()
True
>>> "Ali Sadeghi Aghili" in banner(ascii_only=True)
True
"""
from __future__ import annotations
import logging
import sys
from pathlib import Path
from typing import TextIO
#: Human-readable name of this work, as named in ``LICENSE``.
PROJECT = "Local SQL Agent"
#: The Licensor named in ``LICENSE``. Also the author of the work.
LICENSOR = "Ali Sadeghi Aghili"
#: Copyright years, matching the SPDX headers and ``NOTICE``.
COPYRIGHT_YEARS = "2024-2026"
#: SPDX identifier of the governing licence.
LICENCE_ID = "BUSL-1.1"
#: Date on which the terms convert to :data:`CHANGE_LICENCE`.
CHANGE_DATE = "2029-01-01"
#: Licence the work converts to on :data:`CHANGE_DATE`.
CHANGE_LICENCE = "Apache-2.0"
#: Canonical source of this work.
REPO_URL = "https://github.com/alisadeghiaghili/local-sql-agent"
#: Arbitrary constant unique to this codebase -- see the module docstring's
#: Provenance section. Do not regenerate it: changing it destroys the only
#: thing it exists for.
FINGERPRINT = "ime-nlq-7f3a91c4-2b6d-4e08-9a15-c0de5a1d8b72"
#: The author's own line, written in the language this project exists to
#: answer questions in: "ساخته علی صادقی عقیلی".
#:
#: Escaped rather than written literally so that the source file's own
#: encoding can never garble it in transit through a tool that assumes
#: cp1252 -- which, on this project's target platform, several do.
SIGNATURE_FA = (
"ساخته"
" علی صادقی عقیلی"
)
#: Files whose absence means the licence terms have been separated from the
#: code. Their absence changes nothing about the terms themselves.
_LICENCE_FILES = ("LICENSE", "NOTICE", "AGENTS.md")
#: Repository root, resolved from this file rather than from the working
#: directory -- the same reasoning as ``api/server.py``'s ``_PROMPT_PATH``.
_ROOT = Path(__file__).resolve().parent.parent
logger = logging.getLogger(__name__)
def missing_licence_files() -> tuple[str, ...]:
"""Names of :data:`_LICENCE_FILES` absent from this installation.
>>> isinstance(missing_licence_files(), tuple)
True
"""
return tuple(name for name in _LICENCE_FILES if not (_ROOT / name).is_file())
def _stream_can_encode(text: str, stream: TextIO | None = None) -> bool:
"""Whether *text* survives the encoding of *stream* (default stderr).
This project is Persian-first and deployed on Windows, where a console
or service log handler is often still cp1252. ``logging`` swallows a
handler's ``UnicodeEncodeError`` through ``handleError``, so an
unencodable banner does not crash the process -- it silently fails to
appear, which defeats the only purpose a start-up banner has. So ask
first rather than hope.
>>> _stream_can_encode("plain ascii")
True
>>> import io
>>> _stream_can_encode(SIGNATURE_FA, io.TextIOWrapper(io.BytesIO(), "cp1252"))
False
>>> _stream_can_encode(SIGNATURE_FA, io.TextIOWrapper(io.BytesIO(), "utf-8"))
True
"""
target = stream if stream is not None else sys.stderr
encoding = getattr(target, "encoding", None) or "ascii"
try:
text.encode(encoding, errors="strict")
except (UnicodeEncodeError, LookupError):
return False
return True
def banner(*, ascii_only: bool = False) -> str:
"""The start-up notice, as a multi-line string.
Deliberately short. A banner long enough to be scrolled past is a
banner nobody reads, which defeats the point of having one.
*ascii_only* drops the Persian signature line for a log stream that
cannot carry it. The line is dropped rather than transliterated: a
mangled rendering of the author's name is worse than its absence.
"""
lines = [
f"{PROJECT} - (c) {COPYRIGHT_YEARS} {LICENSOR} - {LICENCE_ID}",
" Non-production use is granted. Production use of any kind,",
" including internal production use, requires a written agreement",
f" with the Licensor. Converts to {CHANGE_LICENCE} on {CHANGE_DATE}.",
f" LICENSE | NOTICE | AGENTS.md | {REPO_URL}",
f" build {FINGERPRINT}",
]
if not ascii_only:
lines.insert(1, f" {SIGNATURE_FA}")
return "\n".join(lines)
def tamper_notice(missing: tuple[str, ...]) -> str:
"""The notice logged when licence files have been removed.
Addressed to whoever is operating this copy, who is frequently not the
person who removed them.
>>> "LICENSE" in tamper_notice(("LICENSE",))
True
>>> "Ali Sadeghi Aghili" in tamper_notice(("NOTICE",))
True
"""
return "\n".join(
(
f"This installation of {PROJECT} is missing: {', '.join(missing)}.",
f" It remains the work of {LICENSOR}, licensed under {LICENCE_ID}.",
" Removing those files does not alter the terms and does not grant",
" any right to production use. If you received this copy from",
" someone else, they may not have had the right to give it to you.",
f" Terms and licensing contact: {REPO_URL}",
)
)
def log_startup_notice(target: logging.Logger | None = None) -> None:
"""Emit the banner, and a warning if the licence files are gone.
Called once per process start. Uses ``logging`` rather than ``print``
so it lands wherever the operator already collects logs.
"""
log = target if target is not None else logger
full = banner()
log.info("%s", full if _stream_can_encode(full) else banner(ascii_only=True))
missing = missing_licence_files()
if missing:
log.warning("%s", tamper_notice(missing))