Skip to content

Commit

Permalink
Fix issue regarding the access to user namespaces
Browse files Browse the repository at this point in the history
  • Loading branch information
Hervé Quatremain committed Nov 24, 2024
1 parent 5a97e57 commit 04c5f22
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 18 deletions.
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
namespace: infra
name: quay_configuration
version: 2.4.0
version: 2.5.0
readme: README.md
authors:
- Hervé Quatremain <herve.quatremain@redhat.com>
Expand Down
17 changes: 16 additions & 1 deletion plugins/modules/quay_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@
description:
- Name of the repository which contains the notifications to manage. The
format for the name is C(namespace)/C(shortname). The namespace can be
an organization or a personal namespace.
an organization or your personal namespace.
- If you omit the namespace part in the name, then the module looks for
the repository in your personal namespace.
- You can manage notifications for repositories in your personal
namespace, but not in the personal namespace of other users. The token
you use in O(quay_token) determines the user account you are using.
required: true
type: str
title:
Expand Down Expand Up @@ -453,6 +456,18 @@ def main():
module.fail_json(
msg="The {namespace} namespace does not exist.".format(namespace=namespace)
)
# Make sure that the current user is the owner of that namespace
if (
not namespace_details.get("is_organization")
and namespace_details.get("name") != my_name
):
if my_name:
msg = "You ({user}) are not the owner of {namespace}'s namespace.".format(
user=my_name, namespace=namespace
)
else:
msg = "You cannot access {namespace}'s namespace.".format(namespace=namespace)
module.fail_json(msg=msg)

full_repo_name = "{namespace}/{repository}".format(
namespace=namespace, repository=repo_shortname
Expand Down
37 changes: 26 additions & 11 deletions plugins/modules/quay_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@
description:
- Name of the repository to create, remove, or modify. The format for the
name is C(namespace)/C(shortname). The namespace can be an organization
or a personal namespace.
or your personal namespace.
- The name must be in lowercase and must not contain white spaces.
- If you omit the namespace part in the name, then the module uses your
personal namespace.
- You can manage repositories in your personal namespace,
but not in the personal namespace of other users. The token you use in
O(quay_token) determines the user account you are using.
required: true
type: str
visibility:
Expand Down Expand Up @@ -326,6 +329,27 @@ def main():
).format(name=name)
)

# Check whether namespace exists (organization or user account)
namespace_details = module.get_namespace(namespace)
if not namespace_details:
if state == "absent":
module.exit_json(changed=False)
module.fail_json(
msg="The {namespace} namespace does not exist.".format(namespace=namespace)
)
# Make sure that the current user is the owner of that namespace
if (
not namespace_details.get("is_organization")
and namespace_details.get("name") != my_name
):
if my_name:
msg = "You ({user}) are not the owner of {namespace}'s namespace.".format(
user=my_name, namespace=namespace
)
else:
msg = "You cannot access {namespace}'s namespace.".format(namespace=namespace)
module.fail_json(msg=msg)

full_repo_name = "{namespace}/{repository}".format(
namespace=namespace, repository=repo_shortname
)
Expand All @@ -351,9 +375,7 @@ def main():
# "can_admin": true
# }
repo_details = module.get_object_path(
"repository/{full_repo_name}",
ok_error_codes=[404, 403],
full_repo_name=full_repo_name,
"repository/{full_repo_name}", full_repo_name=full_repo_name
)

# Remove the repository
Expand All @@ -366,13 +388,6 @@ def main():
full_repo_name=full_repo_name,
)

# Check whether namespace exists (organization or user account)
namespace_details = module.get_namespace(namespace)
if not namespace_details:
module.fail_json(
msg="The {namespace} namespace does not exist.".format(namespace=namespace)
)

changed = False
if not repo_details:
# Create the repository
Expand Down
21 changes: 19 additions & 2 deletions plugins/modules/quay_repository_mirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,13 @@
name:
description:
- Name of the existing repository for which the mirror parameters are
configured. The format for the name is C(namespace)/C(shortname). The
namespace can only be an organization namespace.
configured. The format for the name is C(namespace)/C(shortname).The
namespace can be an organization or your personal namespace.
- If you omit the namespace part in the name, then the module looks for
the repository in your personal namespace.
- You can manage mirrors for repositories in your personal
namespace, but not in the personal namespace of other users. The token
you use in O(quay_token) determines the user account you are using.
required: true
type: str
is_enabled:
Expand Down Expand Up @@ -235,6 +240,18 @@ def main():
module.fail_json(
msg="The {namespace} namespace does not exist.".format(namespace=namespace)
)
# Make sure that the current user is the owner of that namespace
if (
not namespace_details.get("is_organization")
and namespace_details.get("name") != my_name
):
if my_name:
msg = "You ({user}) are not the owner of {namespace}'s namespace.".format(
user=my_name, namespace=namespace
)
else:
msg = "You cannot access {namespace}'s namespace.".format(namespace=namespace)
module.fail_json(msg=msg)

full_repo_name = "{namespace}/{repository}".format(
namespace=namespace, repository=repo_shortname
Expand Down
17 changes: 16 additions & 1 deletion plugins/modules/quay_repository_prune.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@
repository:
description:
- Name of the existing repository to configure. The format for the name is
C(namespace)/C(shortname). The namespace can be an organization or a
C(namespace)/C(shortname). The namespace can be an organization or your
personal namespace.
- If you omit the namespace part in the name, then the module looks for
the repository in your personal namespace.
- You can manage auto-pruning policies for repositories in your personal
namespace, but not in the personal namespace of other users. The token
you use in O(quay_token) determines the user account you are using.
required: true
type: str
append:
Expand Down Expand Up @@ -193,6 +196,18 @@ def main():
module.fail_json(
msg="The {namespace} namespace does not exist.".format(namespace=namespace)
)
# Make sure that the current user is the owner of that namespace
if (
not namespace_details.get("is_organization")
and namespace_details.get("name") != my_name
):
if my_name:
msg = "You ({user}) are not the owner of {namespace}'s namespace.".format(
user=my_name, namespace=namespace
)
else:
msg = "You cannot access {namespace}'s namespace.".format(namespace=namespace)
module.fail_json(msg=msg)

full_repo_name = "{namespace}/{repository}".format(
namespace=namespace, repository=repo_shortname
Expand Down
2 changes: 1 addition & 1 deletion plugins/modules/quay_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
name:
description:
- Name of the robot account to create or remove, in the format
C(namespace)+C(shortname). The namespace can be an organization or a
C(namespace)+C(shortname). The namespace can be an organization or your
personal namespace.
- The short name (the part after the C(+) sign) must be in lowercase,
must not contain white spaces, must not start by a digit, and must be
Expand Down
66 changes: 65 additions & 1 deletion tests/integration/targets/check_mode/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
that: result['changed']
fail_msg: The preceding task should have deleted the user account

- name: Ensure user lvasquez does not exist (check mode)
- name: Ensure user lvasquez does not exist
infra.quay_configuration.quay_user:
username: lvasquez
email: newemail@example.com
Expand All @@ -128,4 +128,68 @@
ansible.builtin.assert:
that: result['changed']
fail_msg: The preceding task should have deleted the user account

# Expected errors
- name: ERROR EXPECTED Ensure the user exists (host does not exist)
infra.quay_configuration.quay_user:
username: lvasquez
email: newemail@example.com
state: present
quay_host: http://doesnotexists.local
quay_token: "{{ quay_token }}"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed (host does not exist)
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (host does not exist)

- name: ERROR EXPECTED Ensure the user exists (cannot connect)
infra.quay_configuration.quay_user:
username: lvasquez
email: newemail@example.com
state: present
quay_host: https://locahost:12345
quay_token: "{{ quay_token }}"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed (cannot connect to the API)
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (cannot connect)

- name: ERROR EXPECTED Ensure the user exists (SSL validation)
infra.quay_configuration.quay_user:
username: lvasquez
email: newemail@example.com
state: present
quay_host: "{{ quay_host }}"
quay_token: "{{ quay_token }}"
ignore_errors: true
register: result

- name: Ensure that the task failed (SSL validation)
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (SSL validation)

- name: ERROR EXPECTED Ensure the user exists (credentials)
infra.quay_configuration.quay_user:
username: lvasquez
email: newemail@example.com
state: present
quay_host: "{{ quay_host }}"
quay_token: "AABBCCDDEEFFGGHH"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed (wrong credentials)
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (wrong credentials)
...
21 changes: 21 additions & 0 deletions tests/integration/targets/quay_notification/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,27 @@
that: result['failed']
fail_msg: The preceding task should have failed (missing parameters)

- name: ERROR EXPECTED Access to another user namespace
infra.quay_configuration.quay_notification:
repository: ansibletestuser1/ansibletestrepo
title: Test Quay Notification
event: repo_push
method: quay_notification
config:
name: ansibletestteam1
type: team
state: present
quay_host: "{{ quay_url }}"
quay_token: "{{ quay_token }}"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (not allowed)

- name: Ensure notification of type Quay Notification exists
infra.quay_configuration.quay_notification:
repository: ansibletestorg/ansibletestrepo
Expand Down
15 changes: 15 additions & 0 deletions tests/integration/targets/quay_repository/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
---
- name: ERROR EXPECTED Access to another user namespace
infra.quay_configuration.quay_repository:
name: ansibletestuser1/ansibletestrepo1
state: present
quay_host: "{{ quay_url }}"
quay_token: "{{ quay_token }}"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (not allowed)

- name: Ensure repository ansibletestrepo1 exists
infra.quay_configuration.quay_repository:
name: ansibletestorg/ansibletestrepo1
Expand Down
20 changes: 20 additions & 0 deletions tests/integration/targets/quay_repository_mirror/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,26 @@
that: result['failed']
fail_msg: The preceding task should have failed (missing parameters)

- name: ERROR EXPECTED Access to another user namespace
infra.quay_configuration.quay_repository_mirror:
name: ansibletestuser1/ansibletestrepo1
external_reference: docker.io/library/hello-world
robot_username: ansibletestorg+ansibletestrobot1
image_tags:
- latest
sync_interval: 43200
sync_start_date: "2021-01-01T12:00:00Z"
quay_host: "{{ quay_url }}"
quay_token: "{{ quay_token }}"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (not allowed)

- name: Ensure repository mirror configuration for ansibletestrepo1 exists
infra.quay_configuration.quay_repository_mirror:
name: ansibletestorg/ansibletestrepo1
Expand Down
18 changes: 18 additions & 0 deletions tests/integration/targets/quay_repository_prune/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@
that: result['failed']
fail_msg: The preceding task should have failed (wrong date)

- name: ERROR EXPECTED Access to another user namespace
infra.quay_configuration.quay_repository_prune:
repository: ansibletestuser1/ansibletestrepo
method: tags
value: 5
tag_pattern: "unstable"
tag_pattern_matches: false
quay_host: "{{ quay_url }}"
quay_token: "{{ quay_token }}"
validate_certs: false
ignore_errors: true
register: result

- name: Ensure that the task failed
ansible.builtin.assert:
that: result['failed']
fail_msg: The preceding task should have failed (not allowed)

- name: Ensure a policy does not exist in a non-existing repository (no change)
infra.quay_configuration.quay_repository_prune:
repository: ansibletestorg/nonexisting
Expand Down

0 comments on commit 04c5f22

Please sign in to comment.