Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permission update #46

Merged
merged 20 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a865159
Add an optional field and regex to the config schema and add ressourc…
Nazim-crim Nov 6, 2023
795c361
Add resource_display_name to permission
Nazim-crim Nov 6, 2023
a6bcbb4
Updated permission_synchronizer to allow the use of regex for resourc…
Nazim-crim Nov 6, 2023
d3ef4a0
Fix typing for python 3.5
Nazim-crim Nov 7, 2023
c867e79
fix permission constructor and matching res for backward compatibility
Nazim-crim Nov 8, 2023
59844bd
fixing code lint
Nazim-crim Nov 8, 2023
20fdadd
Changing function and return type to fix typing error
Nazim-crim Nov 8, 2023
c379776
Adding change log and function comments
Nazim-crim Nov 13, 2023
ab65379
Cleaning up code logic in permission synchronizer
Nazim-crim Nov 14, 2023
87b5044
Exclude node modules from check and fix linting
Nazim-crim Nov 15, 2023
39a805b
Fixing doc check and removing security check for node modules
Nazim-crim Nov 15, 2023
2dc57c8
Make key name optional when a regex is used in the config
Nazim-crim Nov 15, 2023
11a133d
Add resource_display_name to magpie handler for testing and regex tes…
Nazim-crim Nov 24, 2023
f0b665e
Modifying function param and return type, fixing comments
Nazim-crim Nov 27, 2023
3357504
Adding stac and thredd sync example in config.example.yml
Nazim-crim Nov 27, 2023
f1d8e94
Fixing test case to check empty permission and fixing config regex
Nazim-crim Nov 28, 2023
9ebcef3
Fixing changes log typos and updating configuration doc
Nazim-crim Nov 29, 2023
9f8e8f6
Removing trailing whitespace
Nazim-crim Nov 29, 2023
fbe120f
Fixing config and updating docs
Nazim-crim Nov 29, 2023
9d25376
Removing :key: and adding double quote
Nazim-crim Nov 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ Changes
`Unreleased <https://github.com/Ouranosinc/cowbird/tree/master>`_ (latest)
------------------------------------------------------------------------------------

* Nothing yet.
* Add optional key ``field`` and ``regex`` to be used in the ``sync_permissions`` section found in the config.
This allows to sync permissions using a field other than ``resource_full_name`` when creating the ``name:type``
from the segment ``ex.: /field1::type1/field2::type2``. Adds support to use ``resource_display_name``.
* The ``regex`` is used to extract the desired information from the ``nametype_path``. It should be used to do an
exact match. This new search overrides the default way of matching each segment with the ``nametype_path``.
In the case where a ``regex`` is found in the target segment, the data will be formed using the same ``resource_type``
for every match in the same segment. Similary, as using ``- name: "**"`` in the config to match multiple segment,
it is possible to use a ``regex`` to match multiple resources in the same segment with ``regex: '(?<=:).*\/?(?=\/)'``

`2.1.0 <https://github.com/Ouranosinc/cowbird/tree/2.1.0>`_ (2023-09-18)
------------------------------------------------------------------------------------
Expand Down
55 changes: 55 additions & 0 deletions config/config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,58 @@ sync_permissions:
- "process_job_status : read -> job_status : read"
# different permission (match), otherwise all jobs/outputs become available.
- "process_job_status : read -> process_description : read-match"
stac_permissions:
services:
api:
stac_collection:
- name: stac
type: service
- name: stac
type: route
- name: collections
type: route
- type: route
field: resource_display_name # Use the resource_display_name for permission mapping.
regex: '[\w]+:[\w\/]+' # This will extract the display name (ex: thredds:birdhouse/testdata/xclim/cmip6).
stac_item:
- name: stac
type: service
- name: stac
type: route
- name: collections
type: route
- name: "{collectionId}"
type: route
- name: items
type: route
- type: route
field: resource_display_name # Use the resource_display_name for permission mapping.
regex: '[\w]+:[\w\/.-]+' # This will extract the display name (ex: thredds:birdhouse/testdata/xclim/cmip6/sic_SImon_CCCma-CanESM5_ssp245_r13i1p2f1_2020.nc)

thredds:
thredd_collection:
- name: thredds
type: service
- type: directory
regex: '(?<=:)[\w\/]+' # Match everything after ":" but before last "/" (ex: thredds:birdhouse/testdata/xclim/cmip6/sic_SImon_CCCma-CanESM5_ssp245_r13i1p2f1_2020.nc
# will match to : birdhouse/testdata/xclim/cmip6). It would be equivalent as matching any number of directory using "**".
thredd_item:
- name: thredds
type: service
- type: directory
regex: '(?<=:).*\/?(?=\/)' # Match everything after ":" but before last "/" example thredds:birdhouse/testdata/xclim/cmip6/sic_SImon_CCCma-CanESM5_ssp245_r13i1p2f1_2020.nc
# will return birdhouse/testdata/xclim/cmip6. This would create recreate the same hierarchy of directories.
- type: file
regex: '[^\/]+$' # Match a file in a leaf directory (ex: sic_SImon_CCCma-CanESM5_ssp245_r13i1p2f1_2020.nc).

permissions_mapping:
# Permission mapping relating to the stac collection mapped to a thredd directory.
- "stac_collection : read-match -> thredd_collection : browse-match"
- "stac_collection : read-allow-recursive -> thredd_collection : browse-allow-recursive"
- "stac_collection : read-deny-match -> thredd_collection : browse-deny-match"
- "stac_collection : read-deny-recursive -> thredd_collection : browse-deny-recursive"
# Permission mapping relating to the stac item mapped to a thredd file.
- "stac_item : read-match -> thredd_item : browse-match"
- "stac_item : read-allow-recursive -> thredd_item : browse-allow-recursive"
- "stac_item : read-deny-match -> thredd_item : browse-deny-match"
- "stac_item : read-deny-recursive -> thredd_item : browse-deny-recursive"
2 changes: 2 additions & 0 deletions cowbird/api/webhooks/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def post_permission_webhook_view(request: Request) -> AnyResponseType:
param_regex_with_slashes = r"^/?[A-Za-z0-9]+(?:[\s_\-\./:][A-Za-z0-9]+)*$"
resource_full_name = ar.get_multiformat_body(request, "resource_full_name",
pattern=param_regex_with_slashes)
resource_display_name = ar.get_multiformat_body(request, "resource_display_name", check_type=(str, type(None)))
name = ar.get_multiformat_body(request, "name")
access = ar.get_multiformat_body(request, "access")
scope = ar.get_multiformat_body(request, "scope")
Expand All @@ -127,6 +128,7 @@ def post_permission_webhook_view(request: Request) -> AnyResponseType:
service_type=service_type,
resource_id=resource_id,
resource_full_name=resource_full_name,
resource_display_name=resource_display_name,
name=name,
access=access,
scope=scope,
Expand Down
36 changes: 19 additions & 17 deletions cowbird/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Any, Dict, List, Literal, Tuple, Union, cast, overload

import yaml
from schema import And, Optional, Regex, Schema
from schema import And, Optional, Or, Regex, Schema

from cowbird.typedefs import (
ConfigDict,
Expand Down Expand Up @@ -191,7 +191,7 @@ def validate_sync_perm_config_schema(sync_cfg: SyncPointConfig) -> None:
"services": {
str: { # Service type, must correspond to an actual Magpie service type
str: [ # Resource key, used to identify the resource here and in the permissions_mapping
{"name": str, "type": str}
{Or("name", "regex", only_one=True): str, "type": str, Optional("field"): str}
Nazim-crim marked this conversation as resolved.
Show resolved Hide resolved
]
}
},
Expand All @@ -213,21 +213,23 @@ def validate_and_get_resource_info(res_key: str, segments: List[ConfigSegment])
named_tokens = set()
has_multi_token = False
for seg in segments:
if seg["name"] == MULTI_TOKEN:
if has_multi_token:
raise ConfigErrorInvalidTokens(f"Invalid config value for resource key {res_key}. Only one "
f"`{MULTI_TOKEN}` token is permitted per resource.")
has_multi_token = True
else:
matched_groups = re.match(NAMED_TOKEN_REGEX, seg["name"])
if matched_groups:
# Save the first group as a named token, since there's only 1 matching group in the regex.
if matched_groups.groups()[0] in named_tokens:
raise ConfigErrorInvalidTokens(f"Invalid config value for resource key {res_key}. Named token "
f"{matched_groups.groups()[0]} was found in multiple segments of "
"the resource path. Each named token should only be used once in a "
"resource path.")
named_tokens.add(matched_groups.groups()[0])
if "name" in seg:
if seg["name"] == MULTI_TOKEN:
if has_multi_token:
raise ConfigErrorInvalidTokens(f"Invalid config value for resource key {res_key}. Only one "
f"`{MULTI_TOKEN}` token is permitted per resource.")
has_multi_token = True
else:
matched_groups = re.match(NAMED_TOKEN_REGEX, seg["name"])
if matched_groups:
# Save the first group as a named token, since there's only 1 matching group in the regex.
if matched_groups.groups()[0] in named_tokens:
raise ConfigErrorInvalidTokens(
f"Invalid config value for resource key {res_key}. Named token "
f"{matched_groups.groups()[0]} was found in multiple segments of "
"the resource path. Each named token should only be used once in a "
"resource path.")
named_tokens.add(matched_groups.groups()[0])

return {"has_multi_token": has_multi_token, "named_tokens": named_tokens}

Expand Down
5 changes: 3 additions & 2 deletions cowbird/handlers/impl/magpie.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,14 @@ def delete_permission(self, permissions_data: List[Dict[str, str]]) -> None:
else:
LOGGER.warning("Empty permission data, no permissions to remove.")

def create_resource(self, resource_name: str, resource_type: str, parent_id: Optional[int]) -> int:
def create_resource(self, resource_name: str, resource_type: str, parent_id: Optional[int],
resource_display_name: Optional[str] = None) -> int:
"""
Creates the specified resource in Magpie and returns the created resource id if successful.
"""
resource_data = {
"resource_name": resource_name,
"resource_display_name": resource_name,
"resource_display_name": resource_display_name or resource_name,
"resource_type": resource_type,
"parent_id": parent_id
}
Expand Down
Loading
Loading