Skip to content

Sign all non-Model screen state with SerializableClosure HMAC#3095

Merged
tabuna merged 7 commits intomasterfrom
copilot/fix-all-tests
Apr 12, 2026
Merged

Sign all non-Model screen state with SerializableClosure HMAC#3095
tabuna merged 7 commits intomasterfrom
copilot/fix-all-tests

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 12, 2026

Screen state is serialized and round-tripped through the client. Previously only Closure properties were HMAC-signed; primitives, arrays, and plain objects used bare PHP serialization — unsigned and tamperable.

Changes

src/Screen/Concerns/SignedValue.php (new)

Wraps any non-Model value in a signed SerializableClosure:

$this->payload = new SerializableClosure(static fn () => $value);

When APP_KEY is set, Laravel's EncryptionServiceProvider registers an HMAC signer. Any payload modification throws InvalidSignatureException on deserialization.

src/Screen/Concerns/ModelStateRetrievable.php

__serialize — explicit dispatch replacing the generic getSerializedPropertyValue fallback:

Value type Stored as
Unsaved Model as-is
\Closure SerializableClosure
Saved Model / QueueableCollection ModelIdentifier
Everything else new SignedValue($value)

__unserialize — symmetric type dispatch: SignedValue::restore() calls the captured closure to recover the original value; SerializableClosure::getClosure() returns the original callable; getRestoredPropertyValue() handles ModelIdentifier DB rehydration.

tests/App/Screens/SerializeRetrievableScreen.php

Added ValueObject (a plain readonly DTO), plus typed array $data, float $amount, and ?ValueObject $valueObject properties to exercise non-Model serialization paths.

tests/Unit/Screen/ScreenSerializeTest.php

  • testWithPrimitivesAndStdObject — covers int, string, float, array, stdClass; asserts "hash" present in each serialized payload
  • testWithComplexObject — asserts ValueObject is captured inside a signed SerializableClosure (not a ModelIdentifier), HMAC hash present, correct round-trip, zero DB queries
  • testClosureIsSignedWithAppKey — asserts Signed::$signer is non-null and closure round-trips correctly

Copilot AI and others added 6 commits April 12, 2026 00:13
Agent-Logs-Url: https://github.com/orchidsoftware/platform/sessions/2a210efc-d504-45b6-ac8e-1439fbf6a783

Co-authored-by: tabuna <5102591+tabuna@users.noreply.github.com>
…dChannel/Message, fix select blade, fix RelationTest extraction

Agent-Logs-Url: https://github.com/orchidsoftware/platform/sessions/b5b15b86-7fd7-4874-8ad3-44d91a38d5f1

Co-authored-by: tabuna <5102591+tabuna@users.noreply.github.com>
…ames.php, fix Dusk test stability

Agent-Logs-Url: https://github.com/orchidsoftware/platform/sessions/fdf822a5-9287-4a89-a216-1eeb3950a3ba

Co-authored-by: tabuna <5102591+tabuna@users.noreply.github.com>
…osure tests for screen serialization

Agent-Logs-Url: https://github.com/orchidsoftware/platform/sessions/a71f785a-72a9-4070-86f0-dd831edafcee

Co-authored-by: tabuna <5102591+tabuna@users.noreply.github.com>
@tabuna tabuna marked this pull request as ready for review April 12, 2026 02:57
@tabuna tabuna merged commit 41adc03 into master Apr 12, 2026
88 of 92 checks passed
@tabuna tabuna deleted the copilot/fix-all-tests branch April 12, 2026 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants