Repository navigation
Add identifier field to AnnotatedChallenge subclasses - #10491
Conversation
There was a problem hiding this comment.
i have a few notes about specific implementation details, but i'm onboard with the general plan here
to deprecate domain, i would trigger a DeprecationWarning using python's warning system whenever the user tries to access the domain attribute on these objects. this should be doable by defining __getattribute__. we should also add a changelog entry about this
i think we probably also want to error and/or trigger a DeprecationWarning in init. my initial instinct is passing in both domains and identifier should be considered an error as we can infer one from the other. beyond that, i think we should do one of:
- have these init functions forever continue accepting domain and automatically create an identifier value from it
- init should also trigger a deprecation warning when domain is provided
i personally don't really care which of those we do and think you should go with your preference
to deal with our code tests erroring because of these DeprecationWarnings, you could just ignore the warning in pytest.ini, but i have a slight preference that you fixup our code to ignore it inline like i did for another warnings at #10466. you could do this by, for example, defining your own __hash__ function that just ignores any deprecationwarning added here and calls its parent hash function
i hope this feedback helps!
|
Thanks for the feedback! Working on it.
Why set up ignores in the tests rather than just converting the tests (and/or code under test) to not pass |
ah my comment wasn't clear i also realize now that my link was bad as i misremembered the approach to warnings used in that PR. what i meant to reference was something like: https://github.com/certbot/certbot/pull/10294/files#diff-aa74ccedcdb0e9f365af3d08968229c2edc189ab0eaccbc77f4160b55baece84L172-R179 sorry about that i definitely think converting test and prod code to use the new approach is better than ignores tho! i just think in some cases, doing that will be difficult for example, since we sometimes store these annotated challenge objects in dicts and sets, i'm open to other ideas, but the way i was imagining you'd deal with this would be to define your own hash function on annotated challenge objects that looks something like: this code could then be deleted when the domain attribute is removed from slots entirely hopefully that makes more sense |
FYI pytest.ini has this comment that states it as more than a preference :D : I feel like the same logic should apply to inline So that leaves us with "update every call site to actually do the right thing." The simplest "right thing" that is equivalent to what we do today is to just replace My overall takeaway is: fixing |
|
i'm aware of what pytest.ini says. i think we're talking about different things when it comes to ignoring warnings. my suggestion about catch_warnings and filterwarnings was to fixup the
for the sake of argument, let's say we do want to support installing IP certs with apache and nginx eventually. i don't imagine we'll add support for obtaining IP certs and installing them with both apache and nginx all in a single release of certbot. in the meantime, just replacing |
We already check for IP addresses in main, and return a user-friendly error there: certbot/certbot/src/certbot/_internal/main.py Lines 1428 to 1430 in b02deb3 (that code stays the same in #10495) The question is whether we should additionally check locally at each reference of |
|
that check won't be hit for say first, just convert every second, we can rely on the high level checks the few different places they occur in main.py around our installer API, but do you mind also adding an inline comment to each one saying something like? for our authenticator APIs, including those of apache and nginx, if we expect extra work needs to be done to get them to be able to successfully obtain certs for IP addresses (or if we're just unsure whether they work right now or not), we add a simple check to the top of each of those plugins i'm imagining the code for a check like that looking something like: if getting code coverage on that raise line is difficult, i'd be fine with us not worrying about test coverage there, even if we have to add i do not think we need a check like this in our DNS plugins as we should never get a DNS achall containing an IP identifier maybe/hopefully an approach like this simplifies the problem a fair bit? how does it sound to you? |
|
Yep, that sounds like a great approach. Pushed an update that does basically all of that, except adding coverage for the ConfigurationErrors in http_01.py (nginx and apache flavors). Passes tests other than the coverage tests; I'll add test cases for those two |
|
Alright, pushed with a test update; should pass now. |
bmw
left a comment
There was a problem hiding this comment.
i suggested some changes, but the high level path we're taking here still lgtm!
| return object.__getattribute__(self, name) | ||
|
|
||
| def __hash__(self) -> int: | ||
| return hash(tuple(getattr(self, slot) for slot in self.__slots__ if slot != 'domain')) |
There was a problem hiding this comment.
can we add a comment here like:
| return hash(tuple(getattr(self, slot) for slot in self.__slots__ if slot != 'domain')) | |
| # when domain is removed from __slots__ in the classes below, this method can be deleted as | |
| # we can rely on the implementation the parent class | |
| return hash(tuple(getattr(self, slot) for slot in self.__slots__ if slot != 'domain')) |
also, i'm certainly biased, but i also prefer the approach i suggested earlier of:
def __hash__(self) -> int:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'the domain attribute is deprecated')
return super().__hash__()
because it:
- continues to allow use of the implementation in the parent class
- two objects that have different domain attributes probably shouldn't hash to the same value or compare equal
- makes it more clear that the code is temporary arguably even removing the need for the code comment i'm suggesting here
with that said, if you have a significant preference for your own approach, feel free to leave this as is and just consider adding a comment helping clarify the purpose of this code
There was a problem hiding this comment.
Ah, good call. I think I ran into some issues with the throw warning / catch warning approach and the "just hash the non-domain stuff" approach seemed to make sense. But your arguments here are good, and on trying it again it just works. 🤷🏻
bmw
left a comment
There was a problem hiding this comment.
i had a clarification and a couple suggestions around the changelog, but this otherwise LGTM!
ohemorange
left a comment
There was a problem hiding this comment.
Added a couple suggestions for the deprecation warnings, but otherwise lgtm!
Co-authored-by: ohemorange <[email protected]>
This field is optional to maintain backwards compatibility. Note that
AnnotatedChallengeinherits fromjose.ImmutableMap, which has a check in init that all slots are provided. That check would not allow us to do a backwards-compatible addition, so I implemented an__init__for each of these subclasses that fills the fields without calling the parent__init__, and so doesn't hit an error whenidentifieris absent.I chose to use
acme.messages.Identifierrather thancertbot._internal.san.SANhere because these are wrapped ACME types, so they should use the ACME representation. Also,AnnotatedChallengeis passed to plugins, so we need to pass a type that the plugins can understand.I'd like to mark
domainas deprecated: what's the best way to do that?Part of #10346
/cc @bmw, who noticed the issue with
AnnotatedChallengehere and provided additional feedback here. Note that there's still some work to do to finish excisingdomainassumptions from this portion of the code, but I believe this is the necessary first step and wanted to collect feedback before doing the rest.