1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-03-21 20:59:10 +00:00

github_secrets_info: new module (#11586)

* github_secrets_info: new module

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* clean tests

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* remove pynacl dep

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* fqcn

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* remove excess output

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* just return result as sample

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* only print secrets, adapt tests

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* Update plugins/modules/github_secrets_info.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/github_secrets_info.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/github_secrets_info.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* t is for typing, and typing is what we did

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

* add info_module attributes

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>

---------

Signed-off-by: Thomas Sjögren <konstruktoid@users.noreply.github.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit df9b30448a)
This commit is contained in:
Thomas Sjögren 2026-03-16 20:14:08 +01:00 committed by patchback[bot]
parent 7784fbdf17
commit 698e1ca203
3 changed files with 258 additions and 0 deletions

2
.github/BOTMETA.yml vendored
View file

@ -644,6 +644,8 @@ files:
maintainers: atorrescogollo maintainers: atorrescogollo
$modules/github_secrets.py: $modules/github_secrets.py:
maintainers: konstruktoid maintainers: konstruktoid
$modules/github_secrets_info.py:
maintainers: konstruktoid
$modules/gitlab_: $modules/gitlab_:
keywords: gitlab source_control keywords: gitlab source_control
maintainers: $team_gitlab maintainers: $team_gitlab

View file

@ -0,0 +1,158 @@
#!/usr/bin/python
# Copyright (c) Ansible project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = r"""
module: github_secrets_info
short_description: List GitHub repository or organization secrets
description:
- List secrets in a GitHub repository or organization.
author:
- Thomas Sjögren (@konstruktoid)
version_added: '12.5.0'
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
options:
organization:
description:
- The GitHub username or organization name.
type: str
required: true
aliases: ["org", "username"]
repository:
description:
- The name of the repository.
- If not provided, the listing will be at organization level.
type: str
aliases: ["repo"]
api_url:
description:
- The base URL for the GitHub API.
type: str
default: "https://api.github.com"
token:
description:
- The GitHub token used for authentication.
type: str
required: true
"""
EXAMPLES = r"""
- name: List Github secret
community.general.github_secrets_info:
token: "{{ lookup('ansible.builtin.env', 'GITHUB_TOKEN') }}"
repository: "ansible"
organization: "ansible"
"""
RETURN = r"""
secrets:
description: The list of currently existing secrets.
type: list
elements: dict
returned: success
sample: [
{
"created_at": "2026-01-11T23:19:00Z",
"name": "ANSIBLE",
"updated_at": "2026-02-15T22:18:16Z"
},
]
contains:
name:
description: The name of the secret.
type: str
created_at:
description: The date and time when the secret was created.
type: str
updated_at:
description: The date and time when the secret was last updated.
type: str
"""
import json
import typing as t
from http import HTTPStatus
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
from ansible_collections.community.general.plugins.module_utils import deps
def list_secrets(
module: AnsibleModule,
api_url: str,
headers: dict[str, str],
organization: str,
repository: str,
) -> dict[str, list]:
url = (
f"{api_url}/repos/{organization}/{repository}/actions/secrets"
if repository
else f"{api_url}/orgs/{organization}/actions/secrets"
)
resp, info = fetch_url(module, url, headers=headers, method="GET")
if info["status"] == HTTPStatus.OK:
body = resp.read()
return {"secrets": json.loads(body).get("secrets", [])}
elif info["status"] == HTTPStatus.NOT_FOUND:
return {
"secrets": [],
}
else:
module.fail_json(msg=f"Failed to list secrets: {info}")
def main() -> None:
"""Ansible module entry point."""
argument_spec = {
"organization": {
"type": "str",
"aliases": ["org", "username"],
"required": True,
},
"repository": {"type": "str", "aliases": ["repo"]},
"api_url": {"type": "str", "default": "https://api.github.com"},
"token": {"type": "str", "required": True, "no_log": True},
}
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
)
deps.validate(module)
organization: str = module.params["organization"]
repository: str = module.params["repository"]
api_url: str = module.params["api_url"]
token: str = module.params["token"]
result: dict[str, t.Any] = {}
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
secrets = list_secrets(module, api_url, headers, organization, repository)
result["changed"] = False
result.update(
secrets=secrets["secrets"],
)
module.exit_json(**result)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,98 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
import json
from unittest.mock import MagicMock, patch
import pytest
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
AnsibleExitJson,
exit_json,
fail_json,
set_module_args,
)
from ansible_collections.community.general.plugins.modules import github_secrets_info
GITHUB_SECRETS_RESPONSE = {
"total_count": 2,
"secrets": [
{
"name": "SECRET1",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-02T00:00:00Z",
},
{
"name": "SECRET2",
"created_at": "2026-01-03T00:00:00Z",
"updated_at": "2026-01-04T00:00:00Z",
},
],
}
def make_fetch_url_response(body, status=200):
response = MagicMock()
response.read.return_value = json.dumps(body).encode("utf-8")
info = {"status": status, "msg": f"OK ({len(json.dumps(body))} bytes)"}
return (response, info)
@pytest.fixture(autouse=True)
def patch_module():
with patch.multiple(
"ansible.module_utils.basic.AnsibleModule",
exit_json=exit_json,
fail_json=fail_json,
):
yield
@pytest.fixture
def fetch_url_mock():
with patch.object(github_secrets_info, "fetch_url") as mock:
yield mock
def test_list_repo_secrets(fetch_url_mock):
fetch_url_mock.side_effect = [
make_fetch_url_response(GITHUB_SECRETS_RESPONSE),
make_fetch_url_response({}, status=200),
]
with set_module_args(
{
"organization": "myorg",
"repository": "myrepo",
"token": "ghp_test_token",
}
):
with pytest.raises(AnsibleExitJson) as exc:
github_secrets_info.main()
result = exc.value.args[0]
assert result["changed"] is False
assert result["secrets"] == GITHUB_SECRETS_RESPONSE["secrets"]
def test_fail_list_repo_secrets(fetch_url_mock):
fetch_url_mock.side_effect = [
make_fetch_url_response({}, status=404),
]
with set_module_args(
{
"organization": "myorg",
"repository": "myrepo",
"token": "ghp_test_token",
}
):
with pytest.raises(AnsibleExitJson) as exc:
github_secrets_info.main()
result = exc.value.args[0]
assert result["changed"] is False
assert result["secrets"] == []