{"id":13843753,"url":"https://github.com/mkorman90/regipy","last_synced_at":"2026-01-22T18:06:36.486Z","repository":{"id":34259186,"uuid":"174027008","full_name":"mkorman90/regipy","owner":"mkorman90","description":"Regipy is an os independent python library for parsing offline registry hives","archived":false,"fork":false,"pushed_at":"2025-12-08T00:18:23.000Z","size":16535,"stargazers_count":265,"open_issues_count":7,"forks_count":57,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-12-10T05:45:51.059Z","etag":null,"topics":[],"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/mkorman90.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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":"2019-03-05T21:59:40.000Z","updated_at":"2025-12-06T11:30:35.000Z","dependencies_parsed_at":"2024-03-02T17:27:07.620Z","dependency_job_id":"d78a14cc-52f4-4a02-82d0-bd76319443da","html_url":"https://github.com/mkorman90/regipy","commit_stats":{"total_commits":310,"total_committers":26,"mean_commits":"11.923076923076923","dds":0.7225806451612904,"last_synced_commit":"b536e0976d21eedbb215c0149bf7e9f6c7fce70a"},"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/mkorman90/regipy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkorman90%2Fregipy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkorman90%2Fregipy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkorman90%2Fregipy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkorman90%2Fregipy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkorman90","download_url":"https://codeload.github.com/mkorman90/regipy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkorman90%2Fregipy/sbom","scorecard":{"id":652787,"data":{"date":"2025-08-19T05:35:33Z","repo":{"name":"github.com/mkorman90/regipy","commit":"fbef605ce5493aaa70f17fdde739e95875686db4"},"scorecard":{"version":"v5.1.1","commit":"cd152cb6742c5b8f2f3d2b5193b41d9c50905198"},"score":5.3,"checks":[{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1","Info: detected update tool: RenovateBot: renovate.json:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#dependency-update-tool"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#maintained"}},{"name":"Security-Policy","score":4,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Warn: no linked content found","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#security-policy"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/python-package.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/python-publish.yml:16","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:13","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":2,"reason":"Found 3/11 approved changesets -- score normalized to 2","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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#binary-artifacts"}},{"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/python-package.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/python-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/python-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/python-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/python-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scorecard.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/scorecard.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/scorecard.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/scorecard.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scorecard.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/scorecard.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scorecard.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/scorecard.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/mkorman90/regipy/tests.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:28","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:39","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:28","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:30","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   2 third-party GitHubAction dependencies pinned","Info:   0 out of   9 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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#pinned-dependencies"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#vulnerabilities"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/python-publish.yml:19"],"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#packaging"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#cii-best-practices"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#signed-releases"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#fuzzing"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#sast"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#branch-protection"}},{"name":"CI-Tests","score":8,"reason":"6 out of 7 merged PRs checked by a CI test -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#ci-tests"}},{"name":"Contributors","score":10,"reason":"project has 11 contributing companies or organizations","details":["Info: found contributions from: aboutcode-org, aboutcode-org  and @nexb, clearlydefined, dejacode, gem-security, inveniosoftware, mend, nexB, package-url, spdx, t-rust-org"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#contributors"}}]},"last_synced_at":"2025-08-21T13:53:36.152Z","repository_id":34259186,"created_at":"2025-08-21T13:53:36.152Z","updated_at":"2025-08-21T13:53:36.152Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28030196,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-25T02:00:05.988Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-08-04T17:02:26.353Z","updated_at":"2025-12-25T14:51:31.654Z","avatar_url":"https://github.com/mkorman90.png","language":"Python","funding_links":[],"categories":["Python (1887)","Python"],"sub_categories":[],"readme":"# regipy\n\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/mkorman90/regipy/badge)](https://securityscorecards.dev/viewer/?uri=github.com/mkorman90/regipy)\n\n\u003e **⚠️ Breaking Changes in v6.0.0**\n\u003e\n\u003e Version 6.0.0 includes significant modernization changes:\n\u003e - **Python 3.9+ required** - Dropped support for Python 3.6, 3.7, and 3.8\n\u003e - **`attrs` library removed** - Data classes now use Python's built-in `dataclasses` module\n\u003e - If your code imports internal classes (`Cell`, `VKRecord`, `Value`, `Subkey`) and uses `attrs` functions like `attr.asdict()`, switch to `dataclasses.asdict()`\n\u003e\n\u003e See the [CHANGELOG](CHANGELOG.md) for full details.\n\nRegipy is a python library for parsing offline registry hives (Hive files with REGF header). regipy has a lot of capabilities:\n* Use as a library:\n    * Recurse over the registry hive, from root or a given path and get all subkeys and values\n    * Read specific subkeys and values\n    * Apply transaction logs on a registry hive\n* Command Line Tools\n    * Dump an entire registry hive to json\n    * Apply transaction logs on a registry hive\n    * Compare registry hives\n    * Execute plugins from a robust plugin system (i.e: amcache, shimcache, extract computer name...)\n\n**Requires Python 3.9 or higher.**\n\n## Installation\n\nRegipy latest version can be installed from pypi:\n\n```bash\npip install regipy[full]\n```\n\nNOTE: ``regipy[full]`` installs dependencies that require compilation tools and might take some time.\nIt is possible to install a version with relaxed dependencies, by omitting the ``[full]``.\n\nAlso, it is possible to install from source by cloning the repository and executing:\n```bash\npip install --editable .[full]\n```\n\n\n## CLI\n\n#### Parse the header:\n```bash\nregipy-parse-header ~/Documents/TestEvidence/Registry/SYSTEM\n```\nExample output:\n```\n╒════════════════════════╤══════════╕\n│ signature              │ b'regf'  │\n├────────────────────────┼──────────┤\n│ primary_sequence_num   │ 11639    │\n├────────────────────────┼──────────┤\n│ secondary_sequence_num │ 11638    │\n├────────────────────────┼──────────┤\n│ last_modification_time │ 0        │\n├────────────────────────┼──────────┤\n│ major_version          │ 1        │\n├────────────────────────┼──────────┤\n│ minor_version          │ 5        │\n├────────────────────────┼──────────┤\n│ file_type              │ 0        │\n├────────────────────────┼──────────┤\n│ file_format            │ 1        │\n├────────────────────────┼──────────┤\n│ root_key_offset        │ 32       │\n├────────────────────────┼──────────┤\n│ hive_bins_data_size    │ 10534912 │\n├────────────────────────┼──────────┤\n│ clustering_factor      │ 1        │\n├────────────────────────┼──────────┤\n│ file_name              │ SYSTEM   │\n├────────────────────────┼──────────┤\n│ checksum               │ 0        │\n╘════════════════════════╧══════════╛\n[2019-02-09 13:46:12.111654] WARNING: regipy.cli: Hive is not clean! You should apply transaction logs\n```\n* When parsing the header of a hive, also checksum validation and transaction validations are done\n\n\n#### Dump entire hive to disk (this might take some time)\n```bash\nregipy-dump ~/Documents/TestEvidence/Registry/NTUSER-CCLEANER.DAT -o /tmp/output.json\n```\nregipy-dump util can also output a timeline instead of a JSON, by adding the `-t` flag\n\n\n#### Run relevant plugins on Hive\n```bash\nregipy-plugins-run ~/Documents/TestEvidence/Registry/SYSTEM -o /tmp/plugins_output.json\n```\nThe hive type will be detected automatically and the relevant plugins will be executed.\n[**See the plugins section for more information**](docs/PLUGINS.md)\n\n#### Compare registry hives\nCompare registry hives of the same type and output to CSV (if `-o` is not specified output will be printed to screen)\n```bash\nregipy-diff NTUSER.dat NTUSER_modified.dat -o /tmp/diff.csv\n```\nExample output:\n```\n[2019-02-11 19:49:18.824245] INFO: regipy.cli: Comparing NTUSER.DAT vs NTUSER_modified.DAT\n╒══════════════╤══════════════╤════════════════════════════════════════════════════════════════════════════════╤════════════════════════════════════════════════╕\n│ difference   │ first_hive   │ second_hive                                                                    │ description                                    │\n╞══════════════╪══════════════╪════════════════════════════════════════════════════════════════════════════════╪════════════════════════════════════════════════╡\n│ new_subkey   │              │ 2019-02-11T19:46:31.832134+00:00                                               │ \\Software\\Microsoft\\legitimate_subkey          │\n├──────────────┼──────────────┼────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────┤\n│ new_value    │              │ not_a_malware: c:\\temp\\legitimate_binary.exe @ 2019-02-11 19:45:25.516346+00:00 │ \\Software\\Microsoft\\Windows\\CurrentVersion\\Run │\n╘══════════════╧══════════════╧════════════════════════════════════════════════════════════════════════════════╧════════════════════════════════════════════════╛\n[2019-02-11 19:49:18.825328] INFO: regipy.cli: Detected 2 differences\n```\n\n## Recover a registry hive, using transaction logs:\n```bash\nregipy-process-transaction-logs NTUSER.DAT -p ntuser.dat.log1 -s ntuser.dat.log2 -o recovered_NTUSER.dat\n```\nAfter recovering, compare the hives with registry-diff to see what changed\n\n## Using as a library\n\n#### Initiate the registry hive object\n```python\nfrom regipy.registry import RegistryHive\nreg = RegistryHive('/Users/martinkorman/Documents/TestEvidence/Registry/Vibranium-NTUSER.DAT')\n```\n\n#### Iterate recursively over the entire hive, from root key\n```python\nfor entry in reg.recurse_subkeys(as_json=True):\n    print(entry)\n```\n\n#### Iterate over a key and get all subkeys and their modification time:\n```python\nfor sk in reg.get_key('Software').iter_subkeys():\n    print(sk.name, convert_wintime(sk.header.last_modified).isoformat())\n\nAdobe 2019-02-03T22:05:32.525965\nAppDataLow 2019-02-03T22:05:32.526047\nMcAfee 2019-02-03T22:05:32.526140\nMicrosoft 2019-02-03T22:05:32.526282\nNetscape 2019-02-03T22:05:32.526352\nODBC 2019-02-03T22:05:32.526521\nPolicies 2019-02-03T22:05:32.526592\n```\n\n#### Get the values of a key:\n```python\nreg.get_key('Software\\Microsoft\\Internet Explorer\\BrowserEmulation').get_values(as_json=True)\n[{'name': 'CVListTTL',\n  'value': 0,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'UnattendLoaded',\n  'value': 0,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'TLDUpdates',\n  'value': 0,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'CVListXMLVersionLow',\n  'value': 2097211,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'CVListXMLVersionHigh',\n  'value': None,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'CVListLastUpdateTime',\n  'value': None,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'IECompatVersionHigh',\n  'value': None,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'IECompatVersionLow',\n  'value': 2097211,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False},\n {'name': 'StaleCompatCache',\n  'value': 0,\n  'value_type': 'REG_DWORD',\n  'is_corrupted': False}]\n```\n\n#### Use as a plugin:\n```python\nfrom regipy.plugins.ntuser.ntuser_persistence import NTUserPersistencePlugin\nNTUserPersistencePlugin(reg, as_json=True).run()\n\n{\n\t'Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run': {\n\t\t'timestamp': '2019-02-03T22:10:52.655462',\n\t\t'values': [{\n\t\t\t'name': 'Sidebar',\n\t\t\t'value': '%ProgramFiles%\\\\Windows Sidebar\\\\Sidebar.exe /autoRun',\n\t\t\t'value_type': 'REG_EXPAND_SZ',\n\t\t\t'is_corrupted': False\n\t\t}]\n\t}\n}\n```\n\n#### Run all relevant plugins for a specific hive\n```python\nfrom regipy.plugins.utils import run_relevant_plugins\nreg = RegistryHive('/Users/martinkorman/Documents/TestEvidence/Registry/SYSTEM')\nrun_relevant_plugins(reg, as_json=True)\n\n{\n\t'routes': {},\n\t'computer_name': [{\n\t\t'control_set': 'ControlSet001\\\\Control\\\\ComputerName\\\\ComputerName',\n\t\t'computer_name': 'DESKTOP-5EG84UG',\n\t\t'timestamp': '2019-02-03T22:19:28.853219'\n\t}]\n}\n```\n\n## Validation cases\n[Validation cases report](regipy_tests/validation/plugin_validation.md)\n\nAll new plugins should have one or more basic validation cases (which can be expanded in the future), for example:\n```python\nfrom regipy.plugins.system.bam import BAMPlugin\nfrom regipy_tests.validation.validation import ValidationCase\n\n\nclass NTUserUserAssistValidationCase(ValidationCase):\n    # define your plugin class\n    plugin = BAMPlugin\n    # define the test file name, which should be present in `regipy_tests/data`\n    test_hive_file_name = \"SYSTEM_WIN_10_1709.xz\"\n\n    # Use `expected_entries` to test for presence of a few samples from the plugin results\n    expected_entries = [\n        {\n            \"sequence_number\": 9,\n            \"version\": 1,\n            \"sid\": \"S-1-5-90-0-1\",\n            \"executable\": \"\\\\Device\\\\HarddiskVolume2\\\\Windows\\\\System32\\\\dwm.exe\",\n            \"timestamp\": \"2020-04-19T09:09:35.731816+00:00\",\n            \"key_path\": \"\\\\ControlSet001\\\\Services\\\\bam\\\\state\\\\UserSettings\\\\S-1-5-90-0-1\",\n        }\n    ]\n\n    # OR use `exact_expected_result` to test for an exact result:\n    exact_expected_result = [\n        {\n            \"sequence_number\": 9,\n            \"version\": 1,\n            \"sid\": \"S-1-5-90-0-1\",\n            \"executable\": \"\\\\Device\\\\HarddiskVolume2\\\\Windows\\\\System32\\\\dwm.exe\",\n            \"timestamp\": \"2020-04-19T09:09:35.731816+00:00\",\n            \"key_path\": \"\\\\ControlSet001\\\\Services\\\\bam\\\\state\\\\UserSettings\\\\S-1-5-90-0-1\",\n        },\n        {\n            \"sequence_number\": 8,\n            \"version\": 1,\n            \"sid\": \"S-1-5-90-0-1\",\n            \"executable\": \"\\\\Device\\\\HarddiskVolume2\\\\Windows\\\\System32\\\\cmd.exe\",\n            \"timestamp\": \"2020-04-19T09:09:34.544224+00:00\",\n            \"key_path\": \"\\\\ControlSet001\\\\Services\\\\bam\\\\state\\\\UserSettings\\\\S-1-5-90-0-1\",\n        }\n    ]\n\n    expected_entries_count = 2\n```\n\n## Development\n\n### Setting up for development\n\n```bash\n# Clone the repository\ngit clone https://github.com/mkorman90/regipy.git\ncd regipy\n\n# Install in development mode with all dependencies\npip install -e \".[full,dev]\"\n\n# Install pre-commit hooks\npre-commit install\n```\n\n### Running tests\n\n```bash\n# Run all tests\npytest\n\n# Run specific test files\npytest regipy_tests/tests.py\npytest regipy_tests/cli_tests.py\n\n# Run plugin validation\nPYTHONPATH=. python regipy_tests/validation/plugin_validation.py\n```\n\n### Code quality\n\n```bash\n# Run linter\nruff check .\n\n# Run formatter\nruff format .\n\n# Run type checker\nmypy regipy/\n```\n\n### Testing GitHub Actions Locally\n\nTo test CI workflow changes locally before pushing, use [act](https://github.com/nektos/act):\n\n```bash\n# Install act (Fedora)\nsudo dnf install act-cli\n\n# Install act (macOS)\nbrew install act\n\n# Install act (other)\n# See https://nektosact.com/installation/index.html\n```\n\nMake sure Docker is running, then:\n\n```bash\n# List available jobs\nact -l\n\n# Run the lint job\nact -j lint\n\n# Run all jobs for a push event\nact push\n\n# Run the test job with a specific Python version\nact -j test\n\n# Test the build job from publish workflow (simulates a release)\nact release -j build --eventpath /dev/stdin \u003c\u003c\u003c '{\"action\": \"published\"}'\n```\n\nNote: Some jobs may require secrets. You can provide them with:\n\n```bash\nact -j publish --secret PYPI_API_TOKEN=your_token\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkorman90%2Fregipy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkorman90%2Fregipy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkorman90%2Fregipy/lists"}