Skip to content

Commit

Permalink
Add --allowed-packges to remotes to limit what references a remote …
Browse files Browse the repository at this point in the history
…can supply (#15464)

* Initial work for recipe filters per remote

* Remove extra verbose logging

* Address review comments

* Address review comments

* Add test for the resolve_range path

* Rename to --allowed-packages

* Fix test

* Add shorthand syntax to --allowed-packages
  • Loading branch information
AbrilRBS authored Jan 19, 2024
1 parent 7bde83e commit 8c21caf
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 81 deletions.
10 changes: 7 additions & 3 deletions conan/api/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@

class Remote:

def __init__(self, name, url, verify_ssl=True, disabled=False):
def __init__(self, name, url, verify_ssl=True, disabled=False, allowed_packages=None):
self._name = name # Read only, is the key
self.url = url
self.verify_ssl = verify_ssl
self.disabled = disabled
self.allowed_packages = allowed_packages

@property
def name(self):
Expand All @@ -29,8 +30,11 @@ def __eq__(self, other):
self.verify_ssl == other.verify_ssl and self.disabled == other.disabled)

def __str__(self):
return "{}: {} [Verify SSL: {}, Enabled: {}]".format(self.name, self.url, self.verify_ssl,
not self.disabled)
allowed_msg = ""
if self.allowed_packages:
allowed_msg = ", Allowed packages: {}".format(", ".join(self.allowed_packages))
return "{}: {} [Verify SSL: {}, Enabled: {}{}]".format(self.name, self.url, self.verify_ssl,
not self.disabled, allowed_msg)

def __repr__(self):
return str(self)
Expand Down
4 changes: 2 additions & 2 deletions conan/api/subapi/remotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ def remove(self, pattern: str):
RemoteRegistry(self._remotes_file).remove(remote.name)
users_clean(app.cache.localdb, remote.url)

def update(self, remote_name, url=None, secure=None, disabled=None, index=None):
def update(self, remote_name, url=None, secure=None, disabled=None, index=None, allowed_packages=None):
RemoteRegistry(self._remotes_file).update(remote_name, url, secure, disabled=disabled,
index=index)
index=index, allowed_packages=allowed_packages)

def rename(self, remote_name: str, new_name: str):
RemoteRegistry(self._remotes_file).rename(remote_name, new_name)
Expand Down
10 changes: 7 additions & 3 deletions conan/cli/commands/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ def remote_add(conan_api, parser, subparser, *args):
help="Insert the remote at a specific position in the remote list")
subparser.add_argument("-f", "--force", action='store_true',
help="Force the definition of the remote even if duplicated")
subparser.add_argument("-ap", "--allowed-packages", action="append", default=None,
help="Add recipe reference pattern to list of allowed packages for this remote")
subparser.set_defaults(secure=True)
args = parser.parse_args(*args)
r = Remote(args.name, args.url, args.secure, disabled=False)
r = Remote(args.name, args.url, args.secure, disabled=False, allowed_packages=args.allowed_packages)
conan_api.remotes.add(r, force=args.force, index=args.index)


Expand Down Expand Up @@ -102,11 +104,13 @@ def remote_update(conan_api, parser, subparser, *args):
help="Allow insecure server connections when using SSL")
subparser.add_argument("--index", action=OnceArgument, type=int,
help="Insert the remote at a specific position in the remote list")
subparser.add_argument("-ap", "--allowed-packages", action="append", default=None,
help="Add recipe reference pattern to list of allowed packages for this remote")
subparser.set_defaults(secure=None)
args = parser.parse_args(*args)
if args.url is None and args.secure is None and args.index is None:
if args.url is None and args.secure is None and args.index is None and args.allowed_packages is None:
subparser.error("Please add at least one argument to update")
conan_api.remotes.update(args.remote, args.url, args.secure, index=args.index)
conan_api.remotes.update(args.remote, args.url, args.secure, index=args.index, allowed_packages=args.allowed_packages)


@conan_subcommand()
Expand Down
14 changes: 10 additions & 4 deletions conans/client/cache/remote_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ def load(filename):
data = json.loads(text)
for r in data.get("remotes", []):
disabled = r.get("disabled", False)
allowed_packages = r.get("allowed_packages", None)
# TODO: Remote.serialize/deserialize
remote = Remote(r["name"], r["url"], r["verify_ssl"], disabled)
remote = Remote(r["name"], r["url"], r["verify_ssl"], disabled, allowed_packages)
result._remotes[r["name"]] = remote
return result

Expand All @@ -44,6 +45,8 @@ def dumps(self):
remote = {"name": r.name, "url": r.url, "verify_ssl": r.verify_ssl}
if r.disabled:
remote["disabled"] = True
if r.allowed_packages:
remote["allowed_packages"] = r.allowed_packages
remote_list.append(remote)
ret = {"remotes": remote_list}
return json.dumps(ret, indent=True)
Expand Down Expand Up @@ -94,7 +97,7 @@ def _check_urls(self, url, force, current):
else:
ConanOutput().warning(msg + " Adding duplicated remote url because '--force'.")

def update(self, remote_name, url=None, secure=None, disabled=None, index=None, force=False):
def update(self, remote_name, url=None, secure=None, disabled=None, index=None, force=False, allowed_packages=None):
remote = self[remote_name]
if url is not None:
self._check_urls(url, force, remote)
Expand All @@ -110,6 +113,9 @@ def update(self, remote_name, url=None, secure=None, disabled=None, index=None,
remotes.insert(index, remote)
self._remotes = {r.name: r for r in remotes}

if allowed_packages is not None:
remote.allowed_packages = allowed_packages

def items(self):
return list(self._remotes.values())

Expand Down Expand Up @@ -170,11 +176,11 @@ def remove(self, remote_name):
remotes.remove(remote_name)
self.save_remotes(remotes)

def update(self, remote_name, url, secure, disabled, index):
def update(self, remote_name, url, secure, disabled, index, allowed_packages):
if url is not None:
self._validate_url(url)
remotes = self._load_remotes()
remotes.update(remote_name, url, secure, disabled, index)
remotes.update(remote_name, url, secure, disabled, index, allowed_packages=allowed_packages)
self.save_remotes(remotes)

def rename(self, remote, new_name):
Expand Down
4 changes: 4 additions & 0 deletions conans/client/graph/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ def _find_newest_recipe_in_remotes(self, reference, remotes, update, check_updat

results = []
for remote in remotes:
if remote.allowed_packages and not any(reference.matches(f, is_consumer=False)
for f in remote.allowed_packages):
output.debug(f"Excluding remote {remote.name} because recipe is filtered out")
continue
output.info(f"Checking remote: {remote.name}")
try:
if not reference.revision:
Expand Down
4 changes: 4 additions & 0 deletions conans/client/graph/range_resolver.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from conan.api.output import ConanOutput
from conans.errors import ConanException
from conans.model.recipe_ref import RecipeReference
from conans.model.version_range import VersionRange
Expand Down Expand Up @@ -63,6 +64,9 @@ def _resolve_local(self, search_ref, version_range):
return self._resolve_version(version_range, local_found, self._resolve_prereleases)

def _search_remote_recipes(self, remote, search_ref):
if remote.allowed_packages and not any(search_ref.matches(f, is_consumer=False)
for f in remote.allowed_packages):
return []
pattern = str(search_ref)
pattern_cached = self._cached_remote_found.setdefault(pattern, {})
results = pattern_cached.get(remote.name)
Expand Down
Loading

0 comments on commit 8c21caf

Please sign in to comment.