confini

Parse and merge multiple ini files in python3
git clone git://git.defalsify.org/python-confini.git
Log | Files | Refs | README | LICENSE

commit 7e13499798ac9d044dcf32347b6e9721600b1de9
parent 0441a4d0fbb989de97c1527afdaddcd16e43f4ec
Author: nolash <dev@holbrook.no>
Date:   Sat, 17 Oct 2020 16:18:46 +0200

Add readme, test for gpg

Diffstat:
AREADME.md | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfini/config.py | 6+++++-
Aconfini/error.py | 2++
Atest/files/crypt/baz.asc | 14++++++++++++++
Atest/files/crypt/foo.ini | 3+++
Atest/gnupg/openpgp-revocs.d/E3C39E57B5478DF8C9341B1FAC061DE3A30B512E.rev | 35+++++++++++++++++++++++++++++++++++
Atest/gnupg/private-keys-v1.d/31CD2D9AD1C478010F1851D4BA8A4E62473E3206.key | 42++++++++++++++++++++++++++++++++++++++++++
Atest/gnupg/private-keys-v1.d/3331F234B98A55205A42C7C50FE24A5046F57913.key | 42++++++++++++++++++++++++++++++++++++++++++
Atest/gnupg/pubring.kbx | 0
Atest/gnupg/pubring.kbx~ | 0
Atest/gnupg/random_seed | 0
Atest/gnupg/trustdb.gpg | 0
Atest/test_enc.py | 36++++++++++++++++++++++++++++++++++++
13 files changed, 281 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -0,0 +1,102 @@ +# CONFINI + +Configuration parser that process all sections and values in all `ini` files in a directory. + +## Usage + +``` +import confini + +c = confini.Config('/path/to/config/dir') +c.process() + +print(c.get('FOO_BAR_BAZ')) + +``` + +### Value storage + +The values are stored in a single key/value dictionary, with section and name separated by _underscore_ and all letters transformed to uppercase. + +Consider this value in an ini section: + +``` +[foO] +bar_baz = 42 +``` + +This will be stored in the `confini` store with `FOO_BAR_BAZ` as the key. + +### Environment overrides + +By default, the value of any environment variable matching a store key will overwrite the corresponding value in the store. + +A prefix can be provided on instantiation to define a separate namespace for environment variable overrides: + +``` +>>> os.environ.set('FOO_BAZ_BAZ', 666) +>>> c = config.Config('/path/to/config/dir') +>>> c.process() +>>> print(c.get('FOO_BAR_BAZ')) +666 +>>> c = config.Config('/path/to/config/dir', 'XXX') +>>> c.process() +>>> print(c.get('FOO_BAR_BAZ')) +42 +>>> os.environ.set('XXX_FOO_BAZ_BAZ', 13) +>>> c = config.Config('/path/to/config/dir', 'XXX') +>>> c.process() +>>> print(c.get('FOO_BAR_BAZ')) +13 +``` + +### Required values + +Keys can be set as required, and after processing independently validated: + +``` +>>> c = config.Config('/path/to/config/dir') +>>> c.require('BAR_BAZ', 'FOO') +>>> c.process() +>>> c.validate() +True +>>> c = config.Config('/path/to/config/dir') +>>> c.require('BAR_BAZ_BAZ', 'FOO') +>>> c.process() +>>> c.validate() +False +``` + +### Censoring logs + +The string representation of the confini object is a list of all stored values, one on each line. + +Display of individual values can be suppressed: + +``` +>>> c = config.Config('/path/to/config/dir') +>>> c.process() +>>> print(c) +FOO_BAR_BAZ = 666 +>>> c.censor('BAR_BAZ', 'FOO') +>>> print(c) +*** +``` + +### Encryption + +Values can be **GNUPG** encrypted by saving them in individual encrypted files providing the filename as value argument wrapped in a gpg directve: + +``` +[foo] +BAR_BAZ = !gpg(foo_bar_baz.asc) +``` + +Decryption mode must be explicitly activated: + +``` +>>> c = config.Config('/path/to/config/dir', decrypt=True) +``` +The user keyring in the default location is used for decryption. + + diff --git a/confini/config.py b/confini/config.py @@ -8,6 +8,8 @@ import configparser import re import gnupg +from .error import DecryptError + logg = logging.getLogger('confini') current_config = None @@ -128,7 +130,9 @@ class Config: f = open(filename, 'rb') logg.debug('decrypting entry {} in file {}'.format(k, f)) d = gpg.decrypt_file(f) - v =str(d) + if not d.ok: + raise DecryptError() + v = str(d) f.close() return v diff --git a/confini/error.py b/confini/error.py @@ -0,0 +1,2 @@ +class DecryptError(Exception): + pass diff --git a/test/files/crypt/baz.asc b/test/files/crypt/baz.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP MESSAGE----- + +hQGMA8Ll7MXhlLGLAQv/Skj9eYN9MuR2JLIFJ7V2BYgpdakukamW6dCEwr1dyWbq +Uj0UurqSCJBg3qvDQvK2K/UU1ez2+Sot8i/rQY5Q7t9Daxlzp4PombtYw0R3dxLE +bcNCEv7tIr1VjW8cRvkgKc9CamcI2zcUDt2DGq+c9w8Hxn+N7KRF1ZZLGvb7nnTU +ugMyrQb8ILJDyw7ifjgjQFSeh5Kfg+tQAKaPTk7ydCqCXaODd1dCNE1IK/ebl8kT +gGm0db20lcNG9MOmmumD22hTovlouv1WcybpQGzNsogkiJxMRgCQ2DRRAxWOLyam +71iEcCb3w/xf+YISUSWkD+H1W0+2i0X6RTIVNYs/tEnI9/DypKV4wPWcsWbLsVqO +u8wodH5Kk3f/gwVd90wjmpYMrRCIL0/GOfMn8IglN58lOMEtopRtll/CbM8XcRUc +5vsCIcrBiZiwq6bfQxyPSVmpOsxz24BMvU537bVf5qI7KpFn5L5Gjo/Sy1Xq4rpT +avEBM1lXrRbEqXz/fd2J0j4BInKLK3yaAkBq0pFYvCFsHOB/7n0SUkOZcFBXxGGb +sDj+VuQr5hdhJbgyl0ZhsUvHaJQzKFn2N4cW8RQwmw== +=qkyQ +-----END PGP MESSAGE----- diff --git a/test/files/crypt/foo.ini b/test/files/crypt/foo.ini @@ -0,0 +1,3 @@ +[FOO] +bar = 42 +baz = !gpg(baz.asc) diff --git a/test/gnupg/openpgp-revocs.d/E3C39E57B5478DF8C9341B1FAC061DE3A30B512E.rev b/test/gnupg/openpgp-revocs.d/E3C39E57B5478DF8C9341B1FAC061DE3A30B512E.rev @@ -0,0 +1,35 @@ +This is a revocation certificate for the OpenPGP key: + +pub rsa3072 2020-10-17 [SC] [expires: 2022-10-17] + E3C39E57B5478DF8C9341B1FAC061DE3A30B512E +uid Confini Encrypter <dev@holbrook.no> + +A revocation certificate is a kind of "kill switch" to publicly +declare that a key shall not anymore be used. It is not possible +to retract such a revocation certificate once it has been published. + +Use it to revoke this key in case of a compromise or loss of +the secret key. However, if the secret key is still accessible, +it is better to generate a new revocation certificate and give +a reason for the revocation. For details see the description of +of the gpg command "--generate-revocation" in the GnuPG manual. + +To avoid an accidental use of this file, a colon has been inserted +before the 5 dashes below. Remove this colon with a text editor +before importing and publishing this revocation certificate. + +:-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: This is a revocation certificate + +iQG2BCABCAAgFiEE48OeV7VHjfjJNBsfrAYd46MLUS4FAl+K+LACHQAACgkQrAYd +46MLUS7HMQv8DTs3zp74XIDL4coYc4j75MkZOqTdzQea6hlz4cWuzWAkLJi2m19p +qC4vfhT7hvhwr/3/jc1Wd1wd8JkZWRdONU9aBx6NodvjOaCXzacfIBKO7BSIuhoM +aEsLU8tUdigUoO84tpKojIareHxhJcgRIecStPAXru0NtyS0j+z9OznIaqvHW3o9 +yGeTJoHio17nXMH4jkBXNu1PszzPrBE1ttX43sfdwP9goxY5i7oBb+nWG+yFBsBE +168k/dQ2ZWOaInnchqA6gNBWn5R2rK1sVS0v7BDvqXwBeNEohvW4HWarVY3nekv2 +wX3UcrXlg3n8anw2awtBinmh/iZAm11k4KX5r1mAd4Hj4Dwak4DzE9ZmqZeywsMq +ARlkJdh7aG5OWEN9eUKEjj4GVIpr4GhsZvQFTspz4g0uIGfWhTzXyq9EasSUAgLj +De0+dVaC8UDqH5qq1K8e6fweQDodn8ZA80U08BFqeHjkziFUY7JHE+cH3c+1/x1O +6zJxHLAjzCvE +=m9JT +-----END PGP PUBLIC KEY BLOCK----- diff --git a/test/gnupg/private-keys-v1.d/31CD2D9AD1C478010F1851D4BA8A4E62473E3206.key b/test/gnupg/private-keys-v1.d/31CD2D9AD1C478010F1851D4BA8A4E62473E3206.key @@ -0,0 +1,42 @@ +Key: (private-key (rsa (n #00C23A8EE0588FD7889AF41A196C5B20EBEBFECFE495 + 307D818E1942121D6A15DD055150A9F98DD2D03C1C1F4E0419F5A9E781762FA5D465C9 + 593977D90E948ACA553EF8A9C4795FE775C2CCE8E536440192BCCC46DEFE56C9D8FD42 + E9C8681CAAEBC8EF743C8FDB391893B20EB9824ADDF249F3B298238DF1720D9F1AB787 + 6C29FE4CDFEA27747C0C69C518857D56233793F4557C2B9B8C3F9F03B1C8BD77CD2760 + 21BB19E8D1B7B3A02EF1DF6D2E306EB4359B4EC480D1DDB6D62DFA9B25F130C3035D48 + 6BB0470A4DEB109B64A0461A72F93E16C7EA66AF509AF3DAA50B783FE88907956C72AB + 9B24471ED55793D1BFD537C11F05E6323A6E2196D52C6B23F7FCC82566294B7C08374B + 107A2ACB46E2518D62CC822775E3DE8273FE78DF51C7F5E18E24737ACB04F40572CD6B + 9BF80070D58062F6D0B4020F9D93CB015665BCDBECF9696A4A6CDF9F6CED802F63F203 + 54B701E952CFF7F4ED3709638EF1800B482FDB9A59898E016899F3D00D78BADCF88DA9 + 2FFDF62C7280E0544F321AB391#)(e #010001#)(d + #0B238D971B2D20A8C26E3662F7DE600C77ABD4E36094F7D5AABF131573DF6622974F + FB06CC7B903806027CDF1E08191925E03C556E36B8A1ABFECA3B460549D261C22B439D + 3372C714EF578E11BB237A4D9E8B3E934255DADC9965B17F9F4CE9967D1F1274F8B113 + 5CAFF7B9B574DDF34D966525FC68A996CBBA3142387D493C3D4BCE59A0EAA2C4997A46 + B63D226801A3781340FC453EED5522C29AE716CC4AB24E2CEB46F9640626AD1A8CFC37 + 766A9AE62A2281CD7B7BB225255CE671EE1B8AB6C6AA577131852540A002466077AFC1 + 99E30B51CFA573812542C03E1E685A2F0EFF233A0340C4142901C28DC69792EFB0B683 + 7FF7D1F55FFD4D336F791C4B55495BE2BC1F86EF91A42790EFBFA59B65226BFA19F6D1 + 74F28FE9854BB03DC9845E2FD2EBF90D9A465FA463C737CEA33A3DC1A119DC78944456 + CC79C683DF5C8D9E35616465A2F89D1CDDCE33678A46AB74F9800424B4AC714DD4F0B9 + 4BDDA3630E0825DCBAB059B79B43138D43AFD5758815B148D64CAC492858EE1E0E9DEB + #)(p #00DABE83B906C4FF9E184D46DA7B4B081D7E80DC00F731DF14E6CD0D6D673613 + 41CA1CFC0F86E40F9BA45AA0BEAA49191B44400872C08A7786C0522822B122B6584E66 + 418CFDD46F9899E1A46DCC0C0EF98D7C298ED9C88679675973818F301A1F221C0B8C3C + 19B26F791BF57942C64CD801A3A7ED8481C4FC413A4FE9D5F417F36F0EB6F8ABBEE236 + 69EE3C61019180CC1B03364176AF9A67CC6E9036572661D63B30CD679CD55004A85DFC + EF31EABD95AB73F5744DF262F8AFB945385DA5BC07#)(q + #00E34F249CA27D7C0CE6DC31F8DF9C47680ABBB3C596C274CB3E43324DB6E495E41B + 23EF4F313B2FD8E2941F4E63ECCDFE7D945DA05A3F3AB4A2D509E8AFE582CF7D911D39 + FDA44567C6D7C8ACC0C9F4B6AFD9B45A2AACD3B5CBDE09E8471058E173B825A5E2FD68 + 97EF0C9560B808EED33BF0FA37D6F0774C94970B08E9E24B9406D1745C1F179F9F5C6C + 2308F5C88505A868B4655F5D199963C971BFA4AA30AEB85F51801644AB3634E0BFE3EE + FC049FECA6824AE4404DD8A40D9CEF763DDDA7#)(u + #6147AE9A6FDDE93A57916A1711925AE6DBD37E6385F9AAC4B7F0EBA7FD75B48CB3B7 + FFAF030420D634CCC6C91AE3EEBAD0C905D3FF657C56FFA178F81EF39EC410C63AF08E + 6A8292AB8E1700BF3D3E6573D4292359F4C5C43766491AFFDB801AE18C91039CEDA6FF + 7CC019B1F120A4AB0FB51528AD18ED3B2F87CEB6F1A6359385914430CE8A476E20AD09 + E0C7FDDFB553F1C4B51932BF7B5051BD378B294F4B89739627270A39520717BEE45548 + E079FAC33566A27A271745C18E081C1F1455#))) +Created: 20201017T135858 diff --git a/test/gnupg/private-keys-v1.d/3331F234B98A55205A42C7C50FE24A5046F57913.key b/test/gnupg/private-keys-v1.d/3331F234B98A55205A42C7C50FE24A5046F57913.key @@ -0,0 +1,42 @@ +Key: (private-key (rsa (n #00BF82D4D819E69CADF1000B78A38E848A871F610188 + 219B41F66BB4061E5A9A9A2A389D714D3A5D737EAEB28E85B025327810D20CB914C3F9 + 453DF7C29220B5D083D2527798226DB0640A24110F14885B65191BC833B9478D2828A2 + 94339A183ADB8DE672B0E643D05A4E09665C682DC5F00E608306B822907BC9558BF7FA + FE70D71EBA0628C698515B3F0C0B9A71782262677520D3842E501477B93356BAAC017D + B43DF7A7F1BBD1349BB96552EDF8F763DC6FA682FE11962201682730A9BDF683F7FD1A + 4EC5301305418E9713238B86EF1EE31BE60629B3CF92D968942FD66F99DE5CFE1CC859 + 69D267E62CC38A9CEBF49978B521EAF2D5E539E6E8649F66870126DAE0FE121946114B + 9409BCB11FE5249D90FFB2E5247ECAADAC93970D8E2E4C3DD46BCDA07A71B844A7CC7B + 72F96B47571AB2585C63E25BB709C7B986D7516927468896E856A7B4DA06D19BA5DFC1 + 0C6D2F319DF7F1F97B5F03EFFE8D5E9D4F1F0FFE86A7553EA278EA29BDC86C61E08DB3 + 1E0E3D4C430DD04D06CBF2731F#)(e #010001#)(d + #2C1A00D1D3051C47A21C14882F81FE5BB84A2D98A0B4BC803033153DE37791EAB696 + 5B0B6071745BC86C8A89EF9764B97E94C10A5504C72C7C198D18AD7602E885B2C572ED + 01E0A8A22103B539F7CC7EDF852CB4A9D49CF990A9EAE69E0B7A50F38675EF2B759B60 + 3BAB84D6A1A90C016D0AA28709E11574984D00FA3E9CFA431A06E567CDB40E178E1FB2 + B2695A8003CB0D7017A31DE95C5F9A4277E41D10C7371F6EB5BD6319914FC01CAD8CAF + 6889EFE12F84F4DD75475185696ABCF619DC684E947837043E46CF7C3D129C6E542BDA + DA24672EDE88615071F0711EAFE8832D60EF8FEA4A66D20F17E19D7CBC241392BF3E28 + 26D6CAFE8520BBAAD67452187BD01627B52D15558A76F103696102F33C76A49FFF6212 + 169CFAFDB1E8A49676443CC1D73D03E49F5A0F03E3246C4AE4110DC57948669A34D90A + FE3D331F9BBBBCB22681A1C969E30F72F5F01E288248D6A6F044883A87192E633E9B13 + 29A18EB3EF598D5C60A8365638D8F2399016A353B76B9DCFBCE075C09EC3F795D3AA01 + #)(p #00C4C30A3ED4E3D17F8B82CA9D80CCF863308E3F0875BA6E8A20E6E4E1CA3E97 + 5B4C3AACD677F3C8C6FBC22ED4C16116A79479F140A33176BE53B1510BD8C2E136A39C + 1E9360AEB1C81F2CF605D70ADCDAE4E8720FEE00627077E7875F12A5F3A5073813DDBA + 32D66FDF970E5EB509B39E662EA040189D39C706BCFEFC94EF1B8AC6119FE9C2621C2A + 8B932A0AB9A3530267D3DE843FBEBFEF130671ED9D1FFA3DEA6FC5E74BA798C6F187A2 + 6681FED8D6B4A41271EBDC3BE4FE0AAB38BC7AA5C1#)(q + #00F92B18DFC2679FA9286895FDE378B17FE6E6F59C1A18B862301346C6FD7DC74553 + BE791D1879E5D938DCA9C01E7F009B3E7D4880034127988CDD51343DB63E65809C6941 + F4B2D08C4401CA255FE8AE9432EB735D9E74822110DD2B4BE2CF6E1D11F2954434C1F3 + 79150661F555C9F8A5EF2C0810FCC7BCBDB601733652DA61D136E619E6F346DC9364BF + 5765FD9D4F2E71D9B93E6C8E4A9B83C017E82908143C4A0D70D242F89A159B1BC4D3AD + BCAE6C1FB883E204C02FDF91E6879322C010DF#)(u + #009D9B78B4BD7C932FF9639BE75FBB7095B19BE3897D3266F51B964F68193BDF313A + C9CA0B702BE99F66EA1F6EF6397FF2B9D66FAAFE9BD89935DA3940049FB1BA3A3142E4 + C1B5822E8BF4EC739051536C758578B42B0ACC03D95440C5CFA2E378640AE40999EE62 + 70725105A78718B2A69A67E13840576ACB3B8261AEAF9F9EC48B5A25EEC0A9FC2893D7 + A749C2F506DC3F50515B2E6A643E9ABFEC762DEC49CD8D909CD696018DDBCDC9487078 + 0C5299FA0E61E9717733C07C260FE74F4CD3#))) +Created: 20201017T135858 diff --git a/test/gnupg/pubring.kbx b/test/gnupg/pubring.kbx Binary files differ. diff --git a/test/gnupg/pubring.kbx~ b/test/gnupg/pubring.kbx~ Binary files differ. diff --git a/test/gnupg/random_seed b/test/gnupg/random_seed Binary files differ. diff --git a/test/gnupg/trustdb.gpg b/test/gnupg/trustdb.gpg Binary files differ. diff --git a/test/test_enc.py b/test/test_enc.py @@ -0,0 +1,36 @@ +#!/usr/bin/python + +import os +import unittest +import logging + +from confini import Config +from confini.error import DecryptError + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +script_dir = os.path.dirname(os.path.realpath(__file__)) +gnupg_dir = os.path.join(script_dir, 'gnupg') + +class TestBasic(unittest.TestCase): + + wd = os.path.dirname(__file__) + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_enc(self): + inidir = os.path.join(self.wd, 'files/crypt') + c = Config(inidir, decrypt=True) + c.process() + with self.assertRaises(DecryptError): + c.get('FOO_BAZ') + os.environ['GNUPGHOME'] = gnupg_dir + c.get('FOO_BAZ') + +if __name__ == '__main__': + unittest.main()