{"id":15441995,"url":"https://github.com/lincolnloop/goodconf","last_synced_at":"2026-03-04T01:25:06.352Z","repository":{"id":30580289,"uuid":"125443214","full_name":"lincolnloop/goodconf","owner":"lincolnloop","description":"Transparently load variables from environment or JSON/YAML/TOML file.","archived":false,"fork":false,"pushed_at":"2026-02-23T17:56:02.000Z","size":229,"stargazers_count":156,"open_issues_count":6,"forks_count":9,"subscribers_count":15,"default_branch":"main","last_synced_at":"2026-02-24T00:58:15.460Z","etag":null,"topics":["config","configuration","django","env","environment-variables","json","pydantic","python","toml","yaml"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lincolnloop.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGES.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-03-16T00:42:05.000Z","updated_at":"2026-01-01T22:17:00.000Z","dependencies_parsed_at":"2023-12-25T20:10:14.698Z","dependency_job_id":"74d39cb2-420d-42ec-b5a8-c79403886d46","html_url":"https://github.com/lincolnloop/goodconf","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/lincolnloop/goodconf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lincolnloop%2Fgoodconf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lincolnloop%2Fgoodconf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lincolnloop%2Fgoodconf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lincolnloop%2Fgoodconf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lincolnloop","download_url":"https://codeload.github.com/lincolnloop/goodconf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lincolnloop%2Fgoodconf/sbom","scorecard":{"id":590448,"data":{"date":"2025-08-11","repo":{"name":"github.com/lincolnloop/goodconf","commit":"41991d16c6edad6e9362b0b7d7b9f4954a1f2cbe"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.9,"checks":[{"name":"Code-Review","score":5,"reason":"Found 6/12 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:62: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/build.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/lincolnloop/goodconf/test.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/build.yml:21","Warn: pipCommand not pinned by hash: .github/workflows/test.yml:31","Info:   0 out of   7 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of   2 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/build.yml:57","Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/test.yml:9"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":8,"reason":"2 out of the last 2 releases have a total of 2 signed artifacts.","details":["Info: signed release artifact: goodconf-6.0.0-py3-none-any.whl.sigstore: https://github.com/lincolnloop/goodconf/releases/tag/v6.0.0","Info: signed release artifact: goodconf-5.0.0-py3-none-any.whl.sigstore: https://github.com/lincolnloop/goodconf/releases/tag/v5.0.0","Warn: release artifact v6.0.0 does not have provenance: https://api.github.com/repos/lincolnloop/goodconf/releases/178942666","Warn: release artifact v5.0.0 does not have provenance: https://api.github.com/repos/lincolnloop/goodconf/releases/170045643"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":4,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'","Warn: 'stale review dismissal' is disabled on branch 'main'","Warn: branch 'main' does not require approvers","Warn: codeowners review is not required on branch 'main'","Warn: 'last push approval' is disabled on branch 'main'","Info: 'up-to-date branches' is required to merge on branch 'main'","Info: status check found to merge onto on branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/build.yml:29"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T21:44:33.791Z","repository_id":30580289,"created_at":"2025-08-20T21:44:33.791Z","updated_at":"2025-08-20T21:44:33.791Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30068254,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T01:03:42.280Z","status":"ssl_error","status_checked_at":"2026-03-04T01:03:23.410Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["config","configuration","django","env","environment-variables","json","pydantic","python","toml","yaml"],"created_at":"2024-10-01T19:24:44.296Z","updated_at":"2026-03-04T01:25:06.338Z","avatar_url":"https://github.com/lincolnloop.png","language":"Python","readme":"Goodconf\n========\n\n.. image:: https://github.com/lincolnloop/goodconf/actions/workflows/test.yml/badge.svg?branch=main\u0026event=push\n    :target: https://github.com/lincolnloop/goodconf/actions/workflows/test.yml?query=branch%3Amain+event%3Apush\n\n.. image:: https://results.pre-commit.ci/badge/github/lincolnloop/goodconf/main.svg\n    :target: https://results.pre-commit.ci/latest/github/lincolnloop/goodconf/main\n    :alt: pre-commit.ci status\n\n.. image:: https://img.shields.io/codecov/c/github/lincolnloop/goodconf.svg\n    :target: https://codecov.io/gh/lincolnloop/goodconf\n\n.. image:: https://img.shields.io/pypi/v/goodconf.svg\n    :target: https://pypi.python.org/pypi/goodconf\n\n.. image:: https://img.shields.io/pypi/pyversions/goodconf.svg\n    :target: https://pypi.python.org/pypi/goodconf\n\nA thin wrapper over `Pydantic's settings management \u003chttps://pydantic-docs.helpmanual.io/usage/settings/\u003e`__.\nAllows you to define configuration variables and load them from environment or JSON/YAML/TOML\nfile. Also generates initial configuration files and documentation for your\ndefined configuration.\n\n\nInstallation\n------------\n\n``pip install goodconf`` or ``pip install goodconf[yaml]`` /\n``pip install goodconf[toml]`` if parsing/generating YAML/TOML\nfiles is required. When running on Python 3.11+ the ``[toml]``\nextra is only required for generating TOML files as parsing\nis supported natively.\n\n\nQuick Start\n-----------\n\nLet's use configurable Django settings as an example.\n\nFirst, create a ``conf.py`` file in your project's directory, next to\n``settings.py``:\n\n.. code:: python\n\n    import base64\n    import os\n\n    from goodconf import GoodConf, Field\n    from pydantic import PostgresDsn\n\n    class AppConfig(GoodConf):\n        \"Configuration for My App\"\n        DEBUG: bool\n        DATABASE_URL: PostgresDsn = \"postgres://localhost:5432/mydb\"\n        SECRET_KEY: str = Field(\n            initial=lambda: base64.b64encode(os.urandom(60)).decode(),\n            description=\"Used for cryptographic signing. \"\n            \"https://docs.djangoproject.com/en/2.0/ref/settings/#secret-key\")\n\n        model_config = {\"default_files\": [\"/etc/myproject/myproject.yaml\", \"myproject.yaml\"]}\n\n    config = AppConfig()\n\nNext, use the config in your ``settings.py`` file:\n\n.. code:: python\n\n    import dj_database_url\n    from .conf import config\n\n    config.load()\n\n    DEBUG = config.DEBUG\n    SECRET_KEY = config.SECRET_KEY\n    DATABASES = {\"default\": dj_database_url.parse(config.DATABASE_URL)}\n\nIn your initial developer installation instructions, give some advice such as:\n\n.. code:: shell\n\n    python -c \"import myproject; print(myproject.conf.config.generate_yaml(DEBUG=True))\" \u003e myproject.yaml\n\nBetter yet, make it a function and `entry point \u003chttps://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation\u003e`__ so you can install\nyour project and run something like ``generate-config \u003e myproject.yaml``.\n\nUsage\n-----\n\n\n``GoodConf``\n^^^^^^^^^^^^\n\nYour subclassed ``GoodConf`` object can include a ``model_config`` dictionary with the following\nattributes:\n\n``file_env_var``\n  The name of an environment variable which can be used for\n  the name of the configuration file to load.\n``default_files``\n  If no file is passed to the ``load`` method, try to load a\n  configuration from these files in order.\n\nIt also has one method:\n\n``load``\n  Trigger the load method during instantiation. Defaults to False.\n\nUse plain-text docstring for use as a header when generating a configuration\nfile.\n\nEnvironment variables always take precedence over variables in the configuration files.\n\nSee Pydantic's docs for examples of loading:\n\n* `Dotenv (.env) files \u003chttps://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support\u003e`_\n* `Docker secrets \u003chttps://pydantic-docs.helpmanual.io/usage/settings/#secret-support\u003e`_\n\n\nFields\n^^^^^^\n\nDeclare configuration values by subclassing ``GoodConf`` and defining class\nattributes which are standard Python type definitions or Pydantic ``FieldInfo``\ninstances generated by the ``Field`` function.\n\nGoodconf can use one extra argument provided to the ``Field`` to define an function\nwhich can generate an initial value for the field:\n\n``initial``\n  Callable to use for initial value when generating a config\n\n\nDjango Usage\n------------\n\nA helper is provided which monkey-patches Django's management commands to\naccept a ``--config`` argument. Replace your ``manage.py`` with the following:\n\n.. code:: python\n\n    # Define your GoodConf in `myproject/conf.py`\n    from myproject.conf import config\n\n    if __name__ == '__main__':\n        config.django_manage()\n\n\nWhy?\n----\n\nI took inspiration from `logan \u003chttps://github.com/dcramer/logan\u003e`__ (used by\nSentry) and `derpconf \u003chttps://github.com/globocom/derpconf\u003e`__ (used by\nThumbor). Both, however used Python files for configuration. I wanted a safer\nformat and one that was easier to serialize data into from a configuration\nmanagement system.\n\nEnvironment Variables\n^^^^^^^^^^^^^^^^^^^^^\n\nI don't like working with environment variables. First, there are potential\nsecurity issues:\n\n1. Accidental leaks via logging or error reporting services.\n2. Child process inheritance (see `ImageTragick \u003chttps://imagetragick.com/\u003e`__\n   for an idea why this could be bad).\n\nSecond, in practice on deployment environments, environment variables end up\ngetting written to a number of files (cron, bash profile, service definitions,\nweb server config, etc.). Not only is it cumbersome, but also increases the\npossibility of leaks via incorrect file permissions.\n\nI prefer a single structured file which is explicitly read by the application.\nI also want it to be easy to run my applications on services like Heroku\nwhere environment variables are the preferred configuration method.\n\nThis module let's me do things the way I prefer in environments I control, but\nstill run them with environment variables on environments I don't control with\nminimal fuss.\n\n\nContribute\n----------\n\nCreate virtual environment and install package and dependencies.\n\n.. code:: shell\n\n    pip install -e \".[tests]\"\n\n\nRun tests\n\n.. code:: shell\n\n    pytest\n\nReleases are done with GitHub Actions whenever a new tag is created. For more information,\nsee `\u003c./.github/workflows/build.yml\u003e`_\n","funding_links":[],"categories":["Python","Utilities"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flincolnloop%2Fgoodconf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flincolnloop%2Fgoodconf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flincolnloop%2Fgoodconf/lists"}