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

Add --allowed-packges to remotes to limit what references a remote can supply #15464

Merged
merged 8 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
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("--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("--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