Commit Graph
4 Commits
Author SHA1 Message Date
Kaspar V 9b795a25cd fix(pghero): update because CVE-2023-22626 (#23190)
There is a vulnerability
[CVE-2023-22626](https://github.com/advisories/GHSA-vf99-xw26-86g5)

```
Name: pghero
Version: 2.8.3
CVE: CVE-2023-22626
GHSA: GHSA-vf99-xw26-86g5
Criticality: High
URL: https://github.com/ankane/pghero/issues/439
Title: Information Disclosure Through EXPLAIN Feature
Solution: upgrade to '>= 3.1.0'
```
2023-01-22 23:09:02 +01:00
Kaspar V ae62e5fa53 Fix/remove calling private method with send in model (#22951)
* fix(status): remove send usage for private unlink_from_conversations

- make unlink_from_conversations public method
- rename unlink_from_conversations to unlink_from_conversations!
- fix send call on private method in statuses_vacuum and batched_remove_status_service

* fix(feeds_vacuum): replace find_in_batches with in_batches

because active record query results should be a little more efficient than
itterating with map and each. Postgres can grasp such lists of ids much quicker
than ruby can.
Will probably make allmost no difference, but cannot hurt either.
2023-01-11 21:57:24 +01:00
Kaspar V 19f78ea8fa linting: RuboCop update, config fixes (#20574)
* fix(rubocop): update gems and add performance and rspec

fix(rubocop): update gems and add performance and rspec

- update present rubocop gems
- add rubocop-rspec and rubocop-performance gems
- move rubocop gems to gem group :development, :test in order to
  make linting in a github action that runs with RAILS_ENV=test possible

* feat(rubocop): disable some annoyance RSpec cops

To mee these prooved to be more annoying than helpful.
If not agreed, they can be enabled any time.

* fix(rubocop): do not ignore spec/**/*

Because rubocop-rspec should lint the specs as well, and they
deserve to be readable in general. It is relevant code, after all.

* fix(rubocop): change ignore db/**/* to db/schema.rb

because rails cops do some lints for migrations.
E.g. reversable migrations linting and more.

* fix(rubocop): tune rules configs

Bunch of commits squashed:

fix(rubocop): enable Layout/LineLength cop

Because this project has code with line lenghts > 500 chars.
This is not good practice at all, so I strongly suggest to
change the practice in the future.

But allow heredoc, URI and comments to still be long lines
and make the default Max: 120 explicit, by repeating it in the
config. To me this max length seems reasonable. Perhaps
a bit more could be ok for some. But > 500 chars in one line
Seems to be way too long IMHO.

fix(rubocop): Metrics/CyclomaticComplexity Max to 12

The default is 7, perhaps quite strict. But 25 is too loose,
the rule becomes pointless like that.

fix(rubocop): AllCops ruby version, cacheing and more info

- fix the target ruby version from 2.5 to 3.0
- have the cop error messages to be more informative and helpful
- enable cacheing in /tmp

fix(rubocop): Metrics/AbcSize to 34 from 115

Rubocops default is 17. If the rule is at 115 is becomes
pointless.

fix(rubocop): Metrics/BlockLength improvements

- instead of ignoring tasks completely, ignore only the
  long blocks that are specific to tasks (task, namespace)
- ignore also concern specific block methods (included, class_methods)

fix(rubocop): Metrics/ClassLength count heredoc array as one line

fix(rubocop): Metrics/MethodLength Max to 25

- the default is 10, but 65 is too loose, so perhaps 25?

fix(rubocop): Metrics/ModuleLength array and heredoc count as one

fix(rubocop): Metrics/PerceivedComplexity to 16 from 25

Rubocops default is 8, so how about only doubling that, instead
of > than tripple it?

fix(rubocop): enable Style/RedundantAssignment

Because I think that this rule would never really hurt,
but improve code quality and readability.

fix(rubocop): enable Style/RescueStandardError

I think everyone that ever had to debug what this can bring
will hopefully agree that this rule totally makes sense.
In the super rare exeptions where this is totally needed,
it can be excluded by disabling comment in that place.

fix(rubocop): Metrics/ParameterLists add explicit defaults and some excludes
2022-12-15 16:39:59 +01:00
Kaspar V 47f0d7021e refactor(vacuum statuses): reduce amount of db queries and load for each query - improve performance (#21487)
* refactor(statuses_vacuum): remove dead code - unused

Method is not called inside class and private.
Clean up dead code.

* refactor(statuses_vacuum): make retention_period present test explicit

This private method only hides functionality.
It is best practice to be as explicit as possible.

* refactor(statuses_vacuum): improve query performance

- fix statuses_scope having sub-select for Account.remote scope by
  `joins(:account).merge(Account.remote)`
- fix statuses_scope unnecessary use of `Status.arel_table[:id].lt`
  because it is inexplicit, bad practice and even slower than normal
  `.where('statuses.id < ?'`
- fix statuses_scope remove select(:id, :visibility) for having reusable
  active record query batches (no re queries)
- fix vacuum_statuses! to use in_batches instead of find_in_batches,
  because in_batches delivers a full blown active record query result,
  in stead of an array - no requeries necessary
- send(:unlink_from_conversations) not to perform another db query, but
  reuse the in_batches result instead.
- remove now obsolete remove_from_account_conversations method
- remove_from_search_index uses array of ids, instead of mapping
  the ids from an array - this should be more efficient
- use the in_batches scope to call delete_all, instead of running
  another db query for this - because it is again more efficient
- add TODO comment for calling models private method with send

* refactor(status): simplify unlink_from_conversations

- add `has_many through:` relation mentioned_accounts
- use model scope local instead of method call `Status#local?`
- more readable add account to inbox_owners when account.local?

* refactor(status): searchable_by way less sub selects

These queries all included a sub-select. Doing the same with a joins
should be more efficient.
Since this method does 5 such queries, this should be significant,
since it technically halves the query count.

This is how it was:

```ruby
[3] pry(main)> Status.first.mentions.where(account: Account.local, silent: false).explain
  Status Load (1.6ms)  SELECT "statuses".* FROM "statuses" WHERE "statuses"."deleted_at" IS NULL ORDER BY "statuses"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Mention Load (1.5ms)  SELECT "mentions".* FROM "mentions" WHERE "mentions"."status_id" = $1 AND "mentions"."account_id" IN (SELECT "accounts"."id" FROM "accounts" WHERE "accounts"."domain" IS NULL) AND "mentions"."silent" = $2  [["status_id", 109382923142288414], ["silent", false]]
=> EXPLAIN for: SELECT "mentions".* FROM "mentions" WHERE "mentions"."status_id" = $1 AND "mentions"."account_id" IN (SELECT "accounts"."id" FROM "accounts" WHERE "accounts"."domain" IS NULL) AND "mentions"."silent" = $2 [["status_id", 109382923142288414], ["silent", false]]
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.15..23.08 rows=1 width=41)
   ->  Seq Scan on accounts  (cost=0.00..10.90 rows=1 width=8)
         Filter: (domain IS NULL)
   ->  Index Scan using index_mentions_on_account_id_and_status_id on mentions  (cost=0.15..8.17 rows=1 width=41)
         Index Cond: ((account_id = accounts.id) AND (status_id = '109382923142288414'::bigint))
         Filter: (NOT silent)
(6 rows)
```

This is how it is with this change:

```ruby
[4] pry(main)> Status.first.mentions.joins(:account).merge(Account.local).active.explain
  Status Load (1.7ms)  SELECT "statuses".* FROM "statuses" WHERE "statuses"."deleted_at" IS NULL ORDER BY "statuses"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Mention Load (0.7ms)  SELECT "mentions".* FROM "mentions" INNER JOIN "accounts" ON "accounts"."id" = "mentions"."account_id" WHERE "mentions"."status_id" = $1 AND "accounts"."domain" IS NULL AND "mentions"."silent" = $2  [["status_id", 109382923142288414], ["silent", false]]
=> EXPLAIN for: SELECT "mentions".* FROM "mentions" INNER JOIN "accounts" ON "accounts"."id" = "mentions"."account_id" WHERE "mentions"."status_id" = $1 AND "accounts"."domain" IS NULL AND "mentions"."silent" = $2 [["status_id", 109382923142288414], ["silent", false]]
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.15..23.08 rows=1 width=41)
   ->  Seq Scan on accounts  (cost=0.00..10.90 rows=1 width=8)
         Filter: (domain IS NULL)
   ->  Index Scan using index_mentions_on_account_id_and_status_id on mentions  (cost=0.15..8.17 rows=1 width=41)
         Index Cond: ((account_id = accounts.id) AND (status_id = '109382923142288414'::bigint))
         Filter: (NOT silent)
(6 rows)
```
2022-11-27 20:41:18 +01:00