ash-project / ash_paper_trail Goto Github PK
View Code? Open in Web Editor NEWThe extension for keeping an audit log of changes to your Ash resources.
Home Page: https://hexdocs.pm/ash_paper_trail
License: MIT License
The extension for keeping an audit log of changes to your Ash resources.
Home Page: https://hexdocs.pm/ash_paper_trail
License: MIT License
Since the changes attribute could include sensitive attributes, it should itself be sensitive.
Should it also be private?
Is your feature request related to a problem? Please describe.
Executing Api.load!(:paper_trail_versions) |> Enum.sort_by(& &1.version_inserted_at) every time is cumbersome.
Describe the solution you'd like
Api.load!(:paper_trail_versions) should be automatically sorted based on version_inserted_at.
If your actor is a string or tuple, we need a way to record it:
paper_trail do
actor_attribute :actor, :string
end
We currently just use Ash.Type.dump_to_embedded(attribute.type, value, [])
to dump values which may not always be what you want.
See original comment from Zach:
#18 (comment)
A couple issues:
authorize?: false
but does this fail if the api has authorize :always
One of my resources has attribute :variants, {:array, MyApp.Feature.EmbeddedType}, allow_nil?: false
which is a union type. What's the preferred Ashy way to derive the Jason.Encoder?
** (EXIT from #PID<0.3411.0>) an exception was raised:
** (Ash.Error.Unknown) Context: resolving data on commit MyApp.Feature.update
Unknown Error
Context: resolving data on perform MyApp.Feature.Version.create
* Context: resolving data on perform MyApp.Feature.Version.create
** (Protocol.UndefinedError) protocol Jason.Encoder not implemented for #MyApp.Feature.EmbeddedTypeA<__meta__: #Ecto.Schema.Metadata<:built, "">, id: "025f3cb7-bbb0-419d-b5df-7971a8deef94", key: #Ash.CiString<"true">, ...> of type MyApp.Feature.EmbeddedTypeA (a struct), Jason.Encoder protocol must always be explicitly implemented.
If you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:
@derive {Jason.Encoder, only: [....]}
defstruct ...
It is also possible to encode all fields, although this should be used carefully to avoid accidentally leaking private information when new fields are added:
@derive Jason.Encoder
defstruct ...
Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:
Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
Protocol.derive(Jason.Encoder, NameOfTheStruct)
. This protocol is implemented for the following type(s): Any, Ash.CiString, Ash.Union, Atom, BitString, Date, DateTime, Decimal, Ecto.Association.NotLoaded, Ecto.Schema.Metadata, Float, Integer, Jason.Fragment, Jason.OrderedObject, List, Map, NaiveDateTime, Time
Instead of using mixins to customize the Version add something like this:
defmodule MyApp.Post.Version do # this is the version
use Ash.Resource,
data_layer: Ash.DataLayer.Ets,
extensions: [AshPaperTrail.Version]
ets do
private? true
end
paper_trail do
source MyApp.Post # add this
attributes_as_attributes [:subject, :body, :tenant]
change_tracking_mode :changes_only
store_action_name? true
end
end
This allows you to have add graphql, policies, relationships, etc and data layers that differ from the source.
I am having some issues with using ash_papertrail and on a model that uses GraphQL. I copied the example from the README, and this is the issue I am seeing
The following code gives me this error:
== Compilation error in file lib/myapp/myapi/resources/sample.ex ==
** (Spark.Error.DslError) [MyApp.Sample]
Multiple values for key :action
deps/ash_paper_trail/lib/resource/transformers/create_version_resource.ex:157: anonymous fn/4 in :elixir_compiler_10.MODULE/1
(elixir 1.15.4) lib/keyword.ex:1048: Keyword.do_merge/6
deps/ash_paper_trail/lib/resource/transformers/create_version_resource.ex:157: (module)
(spark 1.1.22) .../resources/sample.ex:20: Spark.Dsl.before_compile/1
If I remove the mixin, I get this error:
/Users/danieljacobs/git/api/deps/ash_graphql/lib/resource/resource.ex:2326
In field Paper_trail_versions, :_filter_input is not defined in your schema.
Types must exist if referenced.
`
defmodule MyApp.Sample.PaperTrailMixin do
defmacro using(_) do
quote do
graphql do
type :sample_versions
queries do
list :list_versions, action: :read
end
end
end
end
end
defmodule MyApp.Sample do
use Scribble.Resource,
api: MyApp,
extensions: [AshGraphql.Resource, AshPaperTrail.Resource],
authorizers: [Ash.Policy.Authorizer]
attributes do
uuid_primary_key :id
attribute :name, :uuid, allow_nil?: false
create_timestamp :inserted_at
update_timestamp :updated_at
end
graphql do
type :sample
end
paper_trail do
mixin MyApp.Sample.PaperTrailMixin
version_extensions extensions: [AshGraphql.Resource]
end
actions do
defaults [:read]
end
end
`
Does this look familiar?
The following error occurs when trying to run mix ash_postgres.generate_migrations --name add_paper_trail_to_ticket
.
** (ArgumentError) No such entity nil found.
nil.spark_dsl_config()
(spark 0.3.7) lib/spark/dsl/extension.ex:129: Spark.Dsl.Extension.dsl!/1
(spark 0.3.7) lib/spark/dsl/extension.ex:147: Spark.Dsl.Extension.get_entities/2
(ash 2.5.8) lib/ash/resource/info.ex:564: Ash.Resource.Info.attribute/2
(ash_postgres 1.3.3) lib/migration_generator/migration_generator.ex:2135: anonymous fn/4 in AshPostgres.MigrationGenerator.find_reference/3
(elixir 1.14.3) lib/enum.ex:4239: Enum.find_value_list/3
(ash_postgres 1.3.3) lib/migration_generator/migration_generator.ex:2125: anonymous fn/3 in AshPostgres.MigrationGenerator.attributes/2
(elixir 1.14.3) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
You can see the setup here:
scflode/ash_playground#3
Putting this here for posterity as I don't have time to look into it now. There is a flaky test we see every once in a while:
https://github.com/ash-project/ash/actions/runs/8576866425/job/23508559284#step:14:41
Describe the bug
Ash.bulk_destroy!(records, :destroy, %{},
strategy: [:stream, :atomic, :atomic_batches],
return_errors?: true
)
** (KeyError) key :changed? not found in: %{private: %{authorize?: true}, bulk_destroy: %{index: 0}}
ash_archive uses bulk_destroy
.
To Reproduce
Expected behavior
no error
** Runtime
Additional context
It's been quite a while since you released a new version. Could you release a new version?
Request for feedback: I'd like to associated each version with the actor making the change.
The most straightforward approach IMHO would be to create an :actor relationship and manage it automatically. The syntax could be:
paper_trail do
belongs_to_actor Users.User, api: Users, allow_nil?: false
end
An alternative approach would follow the builtin change relate_actor and leave relationship itself to be added via mixin.
paper_trail do
relate_actor :relationship, allow_nil?: false, field: :id
end
Hi,
I was trying to get this package working, and it looks like maybe it's locked to an ancient version of spark? I ended up forking the project, and removing the dependency ( because, in my particular case, I have ash installed, which already has spark as a dependency ).
Not sure what the right path forward is - or if you are even still supporting this code - but wanted to make you aware. Thanks for the nice software!
Ash.Domain
requires that authorization is run impact create_new_version/1
#80
Flow: inserted student_services -> rollback by create action on student_service_versions
Domain config
defmodule ServiceApp.Api do
use Ash.Domain,
extensions: [
AshPaperTrail.Domain
]
authorization do
authorize(:always)
end
end
Error
Is your feature request related to a problem? Please describe.
I have a requirement to add various metadata to each version, e.g. reason_for_change
for auditing compliance.
Describe the solution you'd like
Ideally, the DSL of AshPaperTrail
would allow specifying metadata arguments to accept from the action to merge into the version.
Describe alternatives you've considered
Express the feature either with a change to resource syntax, or with a change to the resource interface
Simple example:
paper_trail do
metadata [:reason_for_change] # <-- will pull the value from that argument of action
end
It may be important to support more advanced uses, like pulling a nested field from the context and naming the key:
paper_trail do
metadata [client_ip: ^context([:client, :remote_ip])]
end
Additional context
For implementation, perhaps we could use a special context to store the metadata:
paper_trail: %{reason_for_change: "fix typo"}
which could then be encoded on each version.
It is currently not possible to have an attribute on the version that is ignored in the change tracking. This creates an issue when you have a attribute that is used for multitenancy and you need that attribute on the resource, but it also will not change and should be ignored from change tracking
We could actually scrub these. When storing the input, we could check the action, see if the value corresponds to a sensitive argument or sensitive attribute, and if so replace it with `**redacted**` in the changes? We would also need to traverse any unions/embeds given and scrub those too.
Originally posted by @zachdaniel in #29 (comment)
My guess is that ash_paper_trail
is not yet optimised for after_batch
.
In my opinion, I think we should implement this.
Is your feature request related to a problem? Please describe.
I have a number of bulk actions that require auditing and atomic actions w/ rollback. For example, a packing list form which updates the ownership of a number of scanned items.
The trouble is that AshPaperTrail
currently interferes with atomicity. :full_diff
tracking mode may not be possible currently, but :changes_only
should be possible to support atomically.
Describe the solution you'd like
The change for create_new_version
should be refactored for support of bulk/atomic operations where possible. Currently, this would probably exclude :full_diff
tracking mode, supporting only :snapshot
and :changes_only
.
Describe alternatives you've considered
In Ash Paper Trail v0.1.2-rc.0, the belongs_to_actor
option will not work if the relationship is not public.
Additional context
Ash 3.0.0-rc.21
Embedded resources always contain a complete snapshot of the new embedded resource. First it should abide by the change_tracking_mode and when set to :changes_only should only include the change. It should also be configurable to be overridden if you want changes only for the resource but snapshots for the embedded resource.
paper_trail do
embedded_resources_change_tracking_mode :changes_only # defaults to the value of change_tracking_mode
end
Thanks for your help with everything so far.
I downloaded the latest patch and now I am getting this error. I have version 1.1.26 of spark according to my mix.lock file.
[nix-shell:~/git/api]$ mix ash_postgres.generate_migrations --name add_versions
== Compilation error in file lib/myapp/myapi/resources/section.ex ==
** (NimbleOptions.ValidationError) unknown options [:source], valid options are: [:manual, :no_attributes?, :name, :destination, :description, :destination_attribute, :validate_destination_attribute?, :source_attribute, :relationship_context, :private?, :not_found_message, :writable?, :read_action, :api, :filter, :filterable?, :sort, :could_be_related_at_creation?, :violation_message]
(spark 1.1.26) lib/spark/dsl/extension.ex:737: Spark.Dsl.Extension.raise_transformer_error/2
(elixir 1.15.4) lib/enum.ex:4830: Enumerable.List.reduce/3
(elixir 1.15.4) lib/enum.ex:2564: Enum.reduce_while/3
/Users/danieljacobs/git/api/lib/scribble/scribe/resources/section.ex:20: (file)
(stdlib 4.3.1.2) erl_eval.erl:748: :erl_eval.do_apply/7
(stdlib 4.3.1.2) erl_eval.erl:961: :erl_eval.expr_list/7
(stdlib 4.3.1.2) erl_eval.erl:454: :erl_eval.expr/6
mix check
is used on this project locally.
We can use a mix check
within a github action to ensure minimum baseline for each PR is reached.
I think we should do this.
Currently the codebase isn't compliant with mix check
, see the output from my local machine below:
❯ mix deps.get
Resolving Hex dependencies...
Resolution completed in 0.193s
Unchanged:
ash 2.14.12
.......
* Getting typable (Hex package)
❯ mix check
==> earmark_parser
........
Compiling lib/ash/resource/dsl.ex (it's taking more than 10s)
warning: * IMPORTANT *
The configuration `use_all_identities_in_manage_relationship` was not set.
It is defaulting to `true` for backwards compatibility.
This configuration must now be manually set, and it should be set to `false`.
If you have just started a new project, or haven't used `manage_relationship` yet, just set the following config:
config :ash, :use_all_identities_in_manage_relationship?, false
If you are currently using `manage_relationship`, please read https://github.com/ash-project/ash/issues/469 before proceeding
lib/ash/actions/managed_relationships.ex:16: (module)
(elixir 1.14.1) src/elixir_compiler.erl:65: :elixir_compiler.dispatch/4
(elixir 1.14.1) src/elixir_compiler.erl:50: :elixir_compiler.compile/3
(elixir 1.14.1) src/elixir_module.erl:379: :elixir_module.eval_form/6
(elixir 1.14.1) src/elixir_module.erl:105: :elixir_module.compile/5
(elixir 1.14.1) src/elixir_lexical.erl:15: :elixir_lexical.run/3
Generated ash app
==> ash_paper_trail
=> running compiler
Compiling 14 files (.ex)
Generated ash_paper_trail app
=> running formatter
** (Mix) mix format failed due to --check-formatted.
The following files are not formatted:
* test/ash_paper_trail_test.exs
* lib/resource/transformers/create_version_resource.ex
* lib/resource/changes/create_new_version.ex
=> running credo
Checking 27 source files ...
Software Design
┃
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:62:22 #(AshPaperTrail.Resource.Info.version_resource)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:54:5 #(AshPaperTrail.Resource.Info.version_extensions)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:49:5 #(AshPaperTrail.Resource.Info.store_action_name?)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:44:5 #(AshPaperTrail.Resource.Info.reference_source?)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:37:10 #(AshPaperTrail.Resource.Info.on_actions)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:35:5 #(AshPaperTrail.Resource.Info.on_actions)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:30:5 #(AshPaperTrail.Resource.Info.mixin)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:25:5 #(AshPaperTrail.Resource.Info.ignore_attributes)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:20:5 #(AshPaperTrail.Resource.Info.change_tracking_mode)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:11:5 #(AshPaperTrail.Resource.Info.belongs_to_actor)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:6:5 #(AshPaperTrail.Resource.Info.attributes_as_attributes)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/transformers/validate_belongs_to_actor.ex:6:22 #(AshPaperTrail.Resource.Transformers.ValidateBelongsToActor.transform)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/transformers/relate_version_resource.ex:11:27 #(AshPaperTrail.Resource.Transformers.RelateVersionResource.transform)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/api/transformers/allow_resource_versions.ex:13:26 #(AshPaperTrail.Api.Transformers.AllowResourceVersions.transform)
Code Readability
┃
┃ [R] → `with` contains only one <- clause and an `else` branch, consider using
┃ `case` instead
┃ lib/resource/transformers/relate_version_resource.ex:8 #(AshPaperTrail.Resource.Transformers.RelateVersionResource.transform)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/tenant.ex:1:11 #(AshPaperTrail.Test.Tenant)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/tag.ex:1:11 #(AshPaperTrail.Test.Posts.Tag)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/post.ex:1:11 #(AshPaperTrail.Test.Posts.Post)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/author.ex:1:11 #(AshPaperTrail.Test.Posts.Author)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/api.ex:1:11 #(AshPaperTrail.Test.Posts.Api)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/articles/registry.ex:1:11 #(AshPaperTrail.Test.Articles.Registry)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/articles/article.ex:1:11 #(AshPaperTrail.Test.Articles.Article)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/articles/api.ex:1:11 #(AshPaperTrail.Test.Articles.Api)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/accounts/user.ex:1:11 #(AshPaperTrail.Test.Accounts.User)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/accounts/news_feed.ex:1:11 #(AshPaperTrail.Test.Accounts.NewsFeed)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/accounts/api.ex:1:11 #(AshPaperTrail.Test.Accounts.Api)
┃ [R] → Modules should have a @moduledoc tag.
┃ lib/registry/registry.ex:1:11 #(AshPaperTrail.Registry)
┃ [R] ↘ The alias `AshPaperTrail.Test.Posts` is not alphabetically ordered among
┃ its group.
┃ test/ash_paper_trail_test.exs:4:29 #(AshPaperTrailTest)
Refactoring opportunities
┃
┃ [F] → Function is too complex (cyclomatic complexity is 20, max is 9).
┃ lib/resource/transformers/create_version_resource.ex:7:7 #(AshPaperTrail.Resource.Transformers.CreateVersionResource.transform)
┃ [F] ↘ Avoid `apply/2` and `apply/3` when the number of arguments is known
┃ lib/resource/transformers/create_version_resource.ex:32 #(AshPaperTrail.Resource.Transformers.CreateVersionResource.transform)
┃ [F] ↘ Avoid `apply/2` and `apply/3` when the number of arguments is known
┃ lib/resource/transformers/create_version_resource.ex:32 #(AshPaperTrail.Resource.Transformers.CreateVersionResource.transform)
Please report incorrect results: https://github.com/rrrene/credo/issues
Analysis took 0.5 seconds (0.1s to load, 0.3s running 64 checks on 27 files)
62 mods/funs, found 3 refactoring opportunities, 14 code readability issues, 14 software design suggestions.
Use `mix credo explain` to explain issues, `mix credo --help` for options.
=> running sobelow
Checking Sobelow version...
14:12:22.624 [warning] Description: 'Authenticity is not established by certificate path validation'
Reason: 'Option {verify, verify_peer} and cacertfile/cacerts is missing'
A new version of Sobelow is available:
mix archive.install hex sobelow
WARNING: Sobelow cannot find the router. If this is a Phoenix application
please use the `--router` flag to specify the router's location.
##############################################
# #
# Running Sobelow - v0.11.1 #
# Created by Griffin Byatt - @griffinbyatt #
# NCC Group - https://nccgroup.trust #
# #
##############################################
RCE.CodeModule: Code Execution in `Code.eval_quoted` - Low Confidence
File: lib/resource/transformers/create_version_resource.ex
Line: 125
Function: transform:7
Variable: quote
-----------------------------------------------
RCE.CodeModule: Code Execution in `Code.eval_quoted` - Low Confidence
File: lib/resource/transformers/create_version_resource.ex
Line: 98
Function: transform:7
Variable: quote
-----------------------------------------------
... SCAN COMPLETE ...
=> running ex_doc
Generating docs...
View "html" docs at "doc/index.html"
View "epub" docs at "doc/ash_paper_trail.epub"
=> running ex_unit
==> sourceror
....
warning: * IMPORTANT *
The configuration `use_all_identities_in_manage_relationship` was not set.
It is defaulting to `true` for backwards compatibility.
This configuration must now be manually set, and it should be set to `false`.
If you have just started a new project, or haven't used `manage_relationship` yet, just set the following config:
config :ash, :use_all_identities_in_manage_relationship?, false
If you are currently using `manage_relationship`, please read https://github.com/ash-project/ash/issues/469 before proceeding
lib/ash/actions/managed_relationships.ex:16: (module)
(elixir 1.14.1) src/elixir_compiler.erl:65: :elixir_compiler.dispatch/4
(elixir 1.14.1) src/elixir_compiler.erl:50: :elixir_compiler.compile/3
(elixir 1.14.1) src/elixir_module.erl:379: :elixir_module.eval_form/6
(elixir 1.14.1) src/elixir_module.erl:105: :elixir_module.compile/5
(elixir 1.14.1) src/elixir_lexical.erl:15: :elixir_lexical.run/3
Generated ash app
==> ash_paper_trail
Compiling 25 files (.ex)
Generated ash_paper_trail app
...............
Finished in 0.2 seconds (0.00s async, 0.2s sync)
15 tests, 0 failures
Randomized with seed 473024
=> running dialyzer
Finding suitable PLTs
Checking PLT...
[:ash, :asn1, :certifi, :comparable, :compiler, :crypto, :decimal, :ecto, :eex, :elixir, :ets, :ex_check, :excoveralls, :git_cli, :git_ops, :hackney, :idna, :jason, :kernel, :logger, :metrics, :mimerl, :mnesia, :nimble_options, :nimble_parsec, :parse_trans, :picosat_elixir, :public_key, :sourceror, :spark, :ssl, :ssl_verify_fun, :stdlib, :stream_data, :syntax_tools, :telemetry, :tools, :typable, :unicode_util_compat]
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Looking up modules in dialyxir_erlang-25.1.2.plt
Finding applications for dialyxir_erlang-25.1.2.plt
Finding modules for dialyxir_erlang-25.1.2.plt
Creating dialyxir_erlang-25.1.2.plt
Looking up modules in dialyxir_erlang-25.1.2.plt
Removing 3 modules from dialyxir_erlang-25.1.2.plt
Checking 18 modules in dialyxir_erlang-25.1.2.plt
Adding 185 modules to dialyxir_erlang-25.1.2.plt
done in 0m33.08s
Finding applications for dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Finding modules for dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Copying dialyxir_erlang-25.1.2.plt to dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Checking 203 modules in dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Adding 253 modules to dialyxir_erlang-25.1.2_elixir-1.14.1.plt
done in 0m37.85s
Finding applications for dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Finding modules for dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Copying dialyxir_erlang-25.1.2_elixir-1.14.1.plt to dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Checking 456 modules in dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Adding 1389 modules to dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
done in 3m3.58s
No :ignore_warnings opt specified in mix.exs and default does not exist.
Starting Dialyzer
[
....
]
Total errors: 2, Skipped: 0, Unnecessary Skips: 0
done in 0m2.82s
lib/registry/transformers/add_resource_versions.ex:16:callback_arg_type_mismatch
The inferred type for the 1st argument is not a
supertype of the expected type for the transform/1 callback
in the Spark.Dsl.Transformer behaviour.
Success type:
atom()
Behaviour callback type:
map()
________________________________________________________________________________
lib/resource/transformers/create_version_resource.ex:39:call
The function call will not succeed.
Ash.DataLayer.Ets.Info.private?(_dsl_state :: map())
breaks the contract
(Ash.Resource.t()) :: boolean()
________________________________________________________________________________
done (warnings were emitted)
Halting VM with exit status 2
=> reprinting errors from formatter
** (Mix) mix format failed due to --check-formatted.
The following files are not formatted:
* test/ash_paper_trail_test.exs
* lib/resource/transformers/create_version_resource.ex
* lib/resource/changes/create_new_version.ex
=> reprinting errors from credo
Checking 27 source files ...
Software Design
┃
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:62:22 #(AshPaperTrail.Resource.Info.version_resource)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:54:5 #(AshPaperTrail.Resource.Info.version_extensions)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:49:5 #(AshPaperTrail.Resource.Info.store_action_name?)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:44:5 #(AshPaperTrail.Resource.Info.reference_source?)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:37:10 #(AshPaperTrail.Resource.Info.on_actions)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:35:5 #(AshPaperTrail.Resource.Info.on_actions)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:30:5 #(AshPaperTrail.Resource.Info.mixin)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:25:5 #(AshPaperTrail.Resource.Info.ignore_attributes)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:20:5 #(AshPaperTrail.Resource.Info.change_tracking_mode)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:11:5 #(AshPaperTrail.Resource.Info.belongs_to_actor)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/info.ex:6:5 #(AshPaperTrail.Resource.Info.attributes_as_attributes)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/transformers/validate_belongs_to_actor.ex:6:22 #(AshPaperTrail.Resource.Transformers.ValidateBelongsToActor.transform)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/resource/transformers/relate_version_resource.ex:11:27 #(AshPaperTrail.Resource.Transformers.RelateVersionResource.transform)
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃ lib/api/transformers/allow_resource_versions.ex:13:26 #(AshPaperTrail.Api.Transformers.AllowResourceVersions.transform)
Code Readability
┃
┃ [R] → `with` contains only one <- clause and an `else` branch, consider using
┃ `case` instead
┃ lib/resource/transformers/relate_version_resource.ex:8 #(AshPaperTrail.Resource.Transformers.RelateVersionResource.transform)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/tenant.ex:1:11 #(AshPaperTrail.Test.Tenant)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/tag.ex:1:11 #(AshPaperTrail.Test.Posts.Tag)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/post.ex:1:11 #(AshPaperTrail.Test.Posts.Post)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/author.ex:1:11 #(AshPaperTrail.Test.Posts.Author)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/posts/api.ex:1:11 #(AshPaperTrail.Test.Posts.Api)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/articles/registry.ex:1:11 #(AshPaperTrail.Test.Articles.Registry)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/articles/article.ex:1:11 #(AshPaperTrail.Test.Articles.Article)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/articles/api.ex:1:11 #(AshPaperTrail.Test.Articles.Api)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/accounts/user.ex:1:11 #(AshPaperTrail.Test.Accounts.User)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/accounts/news_feed.ex:1:11 #(AshPaperTrail.Test.Accounts.NewsFeed)
┃ [R] → Modules should have a @moduledoc tag.
┃ test/support/accounts/api.ex:1:11 #(AshPaperTrail.Test.Accounts.Api)
┃ [R] → Modules should have a @moduledoc tag.
┃ lib/registry/registry.ex:1:11 #(AshPaperTrail.Registry)
┃ [R] ↘ The alias `AshPaperTrail.Test.Posts` is not alphabetically ordered among
┃ its group.
┃ test/ash_paper_trail_test.exs:4:29 #(AshPaperTrailTest)
Refactoring opportunities
┃
┃ [F] → Function is too complex (cyclomatic complexity is 20, max is 9).
┃ lib/resource/transformers/create_version_resource.ex:7:7 #(AshPaperTrail.Resource.Transformers.CreateVersionResource.transform)
┃ [F] ↘ Avoid `apply/2` and `apply/3` when the number of arguments is known
┃ lib/resource/transformers/create_version_resource.ex:32 #(AshPaperTrail.Resource.Transformers.CreateVersionResource.transform)
┃ [F] ↘ Avoid `apply/2` and `apply/3` when the number of arguments is known
┃ lib/resource/transformers/create_version_resource.ex:32 #(AshPaperTrail.Resource.Transformers.CreateVersionResource.transform)
Please report incorrect results: https://github.com/rrrene/credo/issues
Analysis took 0.5 seconds (0.1s to load, 0.3s running 64 checks on 27 files)
62 mods/funs, found 3 refactoring opportunities, 14 code readability issues, 14 software design suggestions.
Use `mix credo explain` to explain issues, `mix credo --help` for options.
=> reprinting errors from sobelow
Checking Sobelow version...
14:12:22.624 [warning] Description: 'Authenticity is not established by certificate path validation'
Reason: 'Option {verify, verify_peer} and cacertfile/cacerts is missing'
A new version of Sobelow is available:
mix archive.install hex sobelow
WARNING: Sobelow cannot find the router. If this is a Phoenix application
please use the `--router` flag to specify the router's location.
##############################################
# #
# Running Sobelow - v0.11.1 #
# Created by Griffin Byatt - @griffinbyatt #
# NCC Group - https://nccgroup.trust #
# #
##############################################
RCE.CodeModule: Code Execution in `Code.eval_quoted` - Low Confidence
File: lib/resource/transformers/create_version_resource.ex
Line: 125
Function: transform:7
Variable: quote
-----------------------------------------------
RCE.CodeModule: Code Execution in `Code.eval_quoted` - Low Confidence
File: lib/resource/transformers/create_version_resource.ex
Line: 98
Function: transform:7
Variable: quote
-----------------------------------------------
... SCAN COMPLETE ...
=> reprinting errors from dialyzer
Finding suitable PLTs
Checking PLT...
[:ash, :asn1, :certifi, :comparable, :compiler, :crypto, :decimal, :ecto, :eex, :elixir, :ets, :ex_check, :excoveralls, :git_cli, :git_ops, :hackney, :idna, :jason, :kernel, :logger, :metrics, :mimerl, :mnesia, :nimble_options, :nimble_parsec, :parse_trans, :picosat_elixir, :public_key, :sourceror, :spark, :ssl, :ssl_verify_fun, :stdlib, :stream_data, :syntax_tools, :telemetry, :tools, :typable, :unicode_util_compat]
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Looking up modules in dialyxir_erlang-25.1.2.plt
Finding applications for dialyxir_erlang-25.1.2.plt
Finding modules for dialyxir_erlang-25.1.2.plt
Creating dialyxir_erlang-25.1.2.plt
Looking up modules in dialyxir_erlang-25.1.2.plt
Removing 3 modules from dialyxir_erlang-25.1.2.plt
Checking 18 modules in dialyxir_erlang-25.1.2.plt
Adding 185 modules to dialyxir_erlang-25.1.2.plt
done in 0m33.08s
Finding applications for dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Finding modules for dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Copying dialyxir_erlang-25.1.2.plt to dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Checking 203 modules in dialyxir_erlang-25.1.2_elixir-1.14.1.plt
Adding 253 modules to dialyxir_erlang-25.1.2_elixir-1.14.1.plt
done in 0m37.85s
Finding applications for dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Finding modules for dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Copying dialyxir_erlang-25.1.2_elixir-1.14.1.plt to dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Looking up modules in dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Checking 456 modules in dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
Adding 1389 modules to dialyxir_erlang-25.1.2_elixir-1.14.1_deps-dev.plt
done in 3m3.58s
No :ignore_warnings opt specified in mix.exs and default does not exist.
Starting Dialyzer
[
....
]
Total errors: 2, Skipped: 0, Unnecessary Skips: 0
done in 0m2.82s
lib/registry/transformers/add_resource_versions.ex:16:callback_arg_type_mismatch
The inferred type for the 1st argument is not a
supertype of the expected type for the transform/1 callback
in the Spark.Dsl.Transformer behaviour.
Success type:
atom()
Behaviour callback type:
map()
________________________________________________________________________________
lib/resource/transformers/create_version_resource.ex:39:call
The function call will not succeed.
Ash.DataLayer.Ets.Info.private?(_dsl_state :: map())
breaks the contract
(Ash.Resource.t()) :: boolean()
________________________________________________________________________________
done (warnings were emitted)
Halting VM with exit status 2
=> finished in 4:49
✓ compiler success in 0:04
✓ ex_doc success in 0:08
✓ ex_unit success in 1:41
✕ credo error code 14 in 0:07
✕ dialyzer error code 2 in 4:45
✕ formatter error code 1 in 0:06
✕ sobelow error code 1 in 0:08
I truncated some stuff but you get the idea
Just a quick note so we don't forget: The getting started guide got truncated somehow, it literally starts with "Then ..." 🤣
Describe the bug
After updating ash_paper_trail to 3e2a7b4,
changeset.ex fails with WithClauseError
* %WithClauseError{term: #Ash.Changeset<domain: Azir.Apy, action_type: :destroy, action: :destroy, tenant: 562558248040, attributes: %{}, atomics: [archived_at: ~U[2024-06-26 00:59:51.367606Z]], relationships: %{}, errors: [], data: %Ash.Changeset.OriginalDataNotAvailable{reason: :atomic_query_update}, context: %{ash_archival: true}, valid?: true>}
(ash 3.0.16) lib/ash/changeset/changeset.ex:807: anonymous fn/2 in Ash.Changeset.run_atomic_change/3
To Reproduce
A minimal set of resource definitions and calls that can reproduce the bug.
Expected behavior
A clear and concise description of what you expected to happen.
Runtime
Additional context
Add any other context about the problem here.
Request for feedback: To provide a more meaningful log of changes, it would be helpful in some instance to record the name of the action that resulted in the creation of the new version.
The syntax that I'm proposing:
paper_trail do
store_action_name? true # default is false
end
When enabled an action_name
attribute would be added to the version's attributes. This attribute would be allow_nil?: true
This would add a new inputs
attribute to the version resource in addtion to the changes
paper_trail do
store_inputs true
end
Describe the bug
Ash.bulk_update!(records, :update, %{field: value},
strategy: [:stream, :atomic, :atomic_batches],
return_errors?: true
)
** (KeyError) key :changed? not found in: %{private: %{authorize?: true}, bulk_update: %{index: 0}}
To Reproduce
Expected behavior
no error
** Runtime
Additional context
The ignore_attributes
always includes :created_at and :updated_at which are hard-coded atom. We should inspect the resource and get the create_timestamp
and update_timestamp
attribute names if they are present.
RFC: For snapshot change tracking, add restore and reverts actions which would require a full diff and snapshot.
Normal validations and policies would apply to the source version
Is your feature request related to a problem? Please describe.
Bulk actions are used for high performance when creating/modifying a large number of records, but ash papertrail does not support bulk actions, so using bulk actions does not result in good performance.
Describe the solution you'd like
If bulk actions are executed, ash papertrail also runs as a bulk action.
Describe alternatives you've considered
I don't have any alternatives.
Express the feature either with a change to resource syntax, or with a change to the resource interface
No syntax changes.
Additional context
paper_trail
change_tracking_mode { MyApp.CustomDumper, :dump, [] }. # or just MyApp.CustomDumper
end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.