Skip to content

fix(plugin): make payload fields additive on hook infos - #627

Merged
wangyb-A merged 2 commits into
mainfrom
fix/plugin-payload-repr
Aug 11, 2026
Merged

fix(plugin): make payload fields additive on hook infos#627
wangyb-A merged 2 commits into
mainfrom
fix/plugin-payload-repr

Conversation

@wangyb-A

@wangyb-A wangyb-A commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #616, which merged before these could be pushed to its branch.
Addresses both review comments on #616 (commit d92013f) — both findings
landed on main with the merge, so they are live today.

1. High: payloads leaked into repr (plugin.py:212)

Dataclass fields appear in the generated repr, and instrumentation logs hook
infos wholesale:

  • aws-durable-execution-sdk-python-otel logs "Durable invocation started: %s", info
    (and the end hook, and the operation hooks) at debug
  • the bundled plugin example logs f"Invocation started: {info}" at info

So merely adding execution_input / execution_result caused customer input
and results — potentially secrets, potentially megabytes — to be written to
logs implicitly, with no plugin asking for it. Reproduced before fixing:

InvocationStartInfo(request_id='r', execution_arn='a', is_first_invocation=True,
                    execution_start_time=None,
                    execution_input={'password': 'hunter2', 'ssn': '123-45-6789'})

Fix: repr=False on both fields. Identity fields (request_id,
execution_arn, timestamps, status) still render, so the repr stays useful.

2. Medium: payloads changed equality and broke hashing (plugin.py:183)

The fields joined the generated __eq__ / __hash__, so the widening was not
additive. Reproduced:

hash(dict input)      : RAISED TypeError: unhashable type: 'dict'
hash(list input)      : RAISED TypeError: unhashable type: 'list'
prior == with-payload : False

execution_input is Any — arbitrary deserialized JSON — so a dict or list
value made a previously hashable InvocationStartInfo unhashable. Both fields
also made infos built from the earlier field set compare unequal to infos
carrying a payload.

Fix: compare=False, hash=False on both. Identity fields still drive
equality, so payload-only differences now compare equal — payloads are
incidental data on what is otherwise an event record.

Testing

  • repr: secret-looking values never appear in either hook info's repr, while
    request_id / execution_arn still do.
  • hashing: stable across dict, list, nested and scalar payloads, and equal to
    the payload-free hash.
  • equality: infos from the prior field set compare equal to payload-carrying
    infos; two different payloads compare equal; identity fields still drive
    inequality.
  • Declaration-level tests pinning Field.repr / Field.compare / Field.hash,
    so the intent survives a refactor of the generated methods.
  • All five verified to fail when the field arguments are removed.
  • 1519 unit tests passing; hatch fmt --check clean.

Worth a maintainer decision (not changed here)

OperationInfo.result / OperationInfo.error from #625 remain in compare and
in repr. They are hashable types, so they do not break hash(), but they
carry operation-level payloads through the same log sites and now differ from
these fields in equality semantics. Aligning them is a small change if you want
consistency.

Addresses the high-severity Codex review comment on #616.

Dataclass fields land in the generated repr, and instrumentation logs
hook infos wholesale: the bundled OTel plugins at debug level, and the
plugin example at info. Customer input and results -- potentially
secrets, potentially megabytes -- would therefore be written to logs
implicitly, just by adding these fields. Reproduced before fixing.

Set repr=False on execution_input and execution_result. Identity fields
still render, so the repr stays useful, and the values remain readable
through the attributes for plugins that deliberately record them.

Adds a regression test asserting secret-looking values never appear in
either hook info's repr, plus one pinning the field declarations.

Refs #616
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 11, 2026 19:45 — with GitHub Actions Inactive
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 11, 2026 19:45 — with GitHub Actions Inactive
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Addresses the medium-severity Codex review comment on #616.

The payload fields joined the generated __eq__ and __hash__, so the
widening was not additive. execution_input holds arbitrary deserialized
JSON, and a dict or list value made a previously hashable
InvocationStartInfo raise TypeError on hash(); both fields also made
infos built from the earlier field set compare unequal to infos
carrying a payload. Both effects were reproduced first.

Set compare=False, hash=False on execution_input and execution_result.
Identity fields still drive equality, so payload-only differences now
compare equal -- payloads are incidental data on what is otherwise an
event record.

Adds tests for hashability across dict, list, nested and scalar
payloads, for equality against the prior field set, and for the field
declarations themselves.

Note OperationInfo.result / OperationInfo.error from #625 remain in
compare. They are hashable types so they do not break hash(), but the
equality asymmetry with these fields is worth a maintainer decision.

Refs #616
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 11, 2026 20:50 — with GitHub Actions Inactive
@wangyb-A
wangyb-A temporarily deployed to ai-pr-review-runtime August 11, 2026 20:50 — with GitHub Actions Inactive
@wangyb-A wangyb-A changed the title fix(plugin): keep payloads out of hook info repr fix(plugin): make payload fields additive on hook infos Aug 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Codex AI review

No actionable findings. Static review only; tests were not run per the review constraints.

Reviewed commit 2edac5ab694c65e2c494bb0ca2c2019842287125. Workflow run

@wangyb-A
wangyb-A merged commit fd39aff into main Aug 11, 2026
30 of 32 checks passed
@wangyb-A
wangyb-A deleted the fix/plugin-payload-repr branch August 11, 2026 20:54
@github-actions

Copy link
Copy Markdown
Contributor

Claude AI review

This PR makes the execution_input / execution_result payload fields additive on the invocation hook infos by adding repr=False, compare=False, hash=False. The change is correct, minimal, and well-tested.

Verified:

  • repr=False stops payloads leaking into the generated repr. The wholesale-logging sites the PR cites are real: execution_plugin.py:206/276, invocation_plugin.py:366/409 (debug), and examples/.../execution_with_plugin.py:28/31 (info). Identity fields still render.
  • compare=False already excludes each field from __eq__/__hash__; the explicit hash=False is redundant but harmless and matches the declaration-pinning test. Fields inherit correctly into InvocationStartInfo/InvocationEndInfo.
  • No regression from widened equality: no consumer uses these infos as dict keys or set members (OperationChangeInfo maps are keyed by operation_id strings), and no OTel/testing/example test asserts whole-object equality or assert_called_once_with on them — existing tests read the attributes directly, which still work.
  • The five new tests are well-formed (imports resolve) and cover repr exclusion, declaration pinning, hashability across dict/list/nested/scalar payloads, equality invariance, and identity-driven inequality.

No actionable findings.

Residual risk (unchanged lines, out of scope): InvocationEndInfo.error and OperationInfo.result/error remain in repr and compare, so error/operation payloads still flow through the same wholesale log sites and now differ from these fields in equality semantics. The author already flags this as a maintainer decision; worth aligning in a follow-up.

Reviewed commit 2edac5ab694c65e2c494bb0ca2c2019842287125. Workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants