Merge pull request 'v4.1.8' (#35) from asonix/changes into asonix/downstream

Reviewed-on: #35
This commit is contained in:
asonix 2023-09-19 15:28:24 +00:00
commit 7dfe02d92e
23 changed files with 153 additions and 274 deletions

View file

@ -1,225 +0,0 @@
version: 2.1
orbs:
ruby: circleci/ruby@2.0.0
node: circleci/node@5.0.3
executors:
default:
parameters:
ruby-version:
type: string
docker:
- image: cimg/ruby:<< parameters.ruby-version >>
environment:
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
CONTINUOUS_INTEGRATION: true
DB_HOST: localhost
DB_USER: root
DISABLE_SIMPLECOV: true
RAILS_ENV: test
- image: cimg/postgres:14.5
environment:
POSTGRES_USER: root
POSTGRES_HOST_AUTH_METHOD: trust
- image: cimg/redis:7.0
commands:
install-system-dependencies:
steps:
- run:
name: Install system dependencies
command: |
sudo apt-get update
sudo apt-get install -y libicu-dev libidn11-dev
install-ruby-dependencies:
parameters:
ruby-version:
type: string
steps:
- run:
command: |
bundle config clean 'true'
bundle config frozen 'true'
bundle config without 'development production'
name: Set bundler settings
- ruby/install-deps:
bundler-version: '2.3.26'
key: ruby<< parameters.ruby-version >>-gems-v1
wait-db:
steps:
- run:
command: dockerize -wait tcp://localhost:5432 -wait tcp://localhost:6379 -timeout 1m
name: Wait for PostgreSQL and Redis
jobs:
build:
docker:
- image: cimg/ruby:3.0-node
environment:
RAILS_ENV: test
steps:
- checkout
- install-system-dependencies
- install-ruby-dependencies:
ruby-version: '3.0'
- node/install-packages:
cache-version: v1
pkg-manager: yarn
- run:
command: |
export NODE_OPTIONS=--openssl-legacy-provider
./bin/rails assets:precompile
name: Precompile assets
- persist_to_workspace:
paths:
- public/assets
- public/packs-test
root: .
test:
parameters:
ruby-version:
type: string
executor:
name: default
ruby-version: << parameters.ruby-version >>
environment:
ALLOW_NOPAM: true
PAM_ENABLED: true
PAM_DEFAULT_SERVICE: pam_test
PAM_CONTROLLED_SERVICE: pam_test_controlled
parallelism: 4
steps:
- checkout
- install-system-dependencies
- run:
command: sudo apt-get install -y ffmpeg imagemagick libpam-dev
name: Install additional system dependencies
- run:
command: bundle config with 'pam_authentication'
name: Enable PAM authentication
- install-ruby-dependencies:
ruby-version: << parameters.ruby-version >>
- attach_workspace:
at: .
- wait-db
- run:
command: ./bin/rails db:create db:schema:load db:seed
name: Load database schema
- ruby/rspec-test
test-migrations:
executor:
name: default
ruby-version: '3.0'
steps:
- checkout
- install-system-dependencies
- install-ruby-dependencies:
ruby-version: '3.0'
- wait-db
- run:
command: ./bin/rails db:create
name: Create database
- run:
command: ./bin/rails db:migrate VERSION=20171010025614
name: Run migrations up to v2.0.0
- run:
command: ./bin/rails tests:migrations:populate_v2
name: Populate database with test data
- run:
command: ./bin/rails db:migrate VERSION=20180514140000
name: Run migrations up to v2.4.0
- run:
command: ./bin/rails tests:migrations:populate_v2_4
name: Populate database with test data
- run:
command: ./bin/rails db:migrate VERSION=20180707154237
name: Run migrations up to v2.4.3
- run:
command: ./bin/rails tests:migrations:populate_v2_4_3
name: Populate database with test data
- run:
command: ./bin/rails db:migrate
name: Run all remaining migrations
- run:
command: ./bin/rails tests:migrations:check_database
name: Check migration result
test-two-step-migrations:
executor:
name: default
ruby-version: '3.0'
steps:
- checkout
- install-system-dependencies
- install-ruby-dependencies:
ruby-version: '3.0'
- wait-db
- run:
command: ./bin/rails db:create
name: Create database
- run:
command: ./bin/rails db:migrate VERSION=20171010025614
name: Run migrations up to v2.0.0
- run:
command: ./bin/rails tests:migrations:populate_v2
name: Populate database with test data
- run:
command: ./bin/rails db:migrate VERSION=20180514140000
name: Run pre-deployment migrations up to v2.4.0
environment:
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
- run:
command: ./bin/rails tests:migrations:populate_v2_4
name: Populate database with test data
- run:
command: ./bin/rails db:migrate VERSION=20180707154237
name: Run migrations up to v2.4.3
environment:
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
- run:
command: ./bin/rails tests:migrations:populate_v2_4_3
name: Populate database with test data
- run:
command: ./bin/rails db:migrate
name: Run all remaining pre-deployment migrations
environment:
SKIP_POST_DEPLOYMENT_MIGRATIONS: true
- run:
command: ./bin/rails db:migrate
name: Run all post-deployment migrations
- run:
command: ./bin/rails tests:migrations:check_database
name: Check migration result
workflows:
version: 2
build-and-test:
jobs:
- build
- test:
matrix:
parameters:
ruby-version:
- '2.7'
- '3.0'
name: test-ruby<< matrix.ruby-version >>
requires:
- build
- test-migrations:
requires:
- build
- test-two-step-migrations:
requires:
- build
- node/run:
cache-version: v1
name: test-webui
pkg-manager: yarn
requires:
- build
version: '16.18'
yarn-run: test:jest

View file

@ -4,6 +4,9 @@ on:
platforms:
required: true
type: string
cache:
type: boolean
default: true
use_native_arm64_builder:
type: boolean
push_to_images:
@ -85,5 +88,5 @@ jobs:
push: ${{ inputs.push_to_images != '' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: ${{ inputs.cache && 'type=gha' || '' }}
cache-to: ${{ inputs.cache && 'type=gha,mode=max' || '' }}

View file

@ -17,6 +17,8 @@ jobs:
push_to_images: |
tootsuite/mastodon
ghcr.io/mastodon/mastodon
# Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages
cache: false
# Only tag with latest when ran against the latest stable branch
# This needs to be updated after each minor version release
flavor: |

15
.github/workflows/test-image-build.yml vendored Normal file
View file

@ -0,0 +1,15 @@
name: Test container image build
on:
pull_request:
permissions:
contents: read
jobs:
build-image:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
uses: ./.github/workflows/build-container-image.yml
with:
platforms: linux/amd64 # Testing only on native platform so it is performant

View file

@ -3,6 +3,22 @@ Changelog
All notable changes to this project will be documented in this file.
## [4.1.8] - 2023-09-19
### Fixed
- Fix post edits not being forwarded as expected ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26936))
- Fix moderator rights inconsistencies ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26729))
- Fix crash when encountering invalid URL ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26814))
- Fix cached posts including stale stats ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26409))
- Fix uploading of video files for which `ffprobe` reports `0/0` average framerate ([NicolaiSoeborg](https://github.com/mastodon/mastodon/pull/26500))
- Fix unexpected audio stream transcoding when uploaded video is eligible to passthrough ([yufushiro](https://github.com/mastodon/mastodon/pull/26608))
### Security
- Fix missing HTML sanitization in translation API (CVE-2023-42452)
- Fix incorrect domain name normalization (CVE-2023-42451)
## [4.1.7] - 2023-09-05
### Changed

View file

@ -17,6 +17,7 @@ COPY Gemfile* package.json yarn.lock /opt/mastodon/
# hadolint ignore=DL3008
RUN apt-get update && \
apt-get -yq dist-upgrade && \
apt-get install -y --no-install-recommends build-essential \
ca-certificates \
git \

View file

@ -28,6 +28,6 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
return if @status.nil?
ActivityPub::ProcessStatusUpdateService.new.call(@status, @object, request_id: @options[:request_id])
ActivityPub::ProcessStatusUpdateService.new.call(@status, @json, @object, request_id: @options[:request_id])
end
end

View file

@ -0,0 +1,9 @@
# frozen_string_literal: true
class Admin::AccountStatusesFilter < AccountStatusesFilter
private
def blocked?
false
end
end

View file

@ -7,18 +7,18 @@ class TagManager
include RoutingHelper
def web_domain?(domain)
domain.nil? || domain.gsub(/[\/]/, '').casecmp(Rails.configuration.x.web_domain).zero?
domain.nil? || domain.delete_suffix('/').casecmp(Rails.configuration.x.web_domain).zero?
end
def local_domain?(domain)
domain.nil? || domain.gsub(/[\/]/, '').casecmp(Rails.configuration.x.local_domain).zero?
domain.nil? || domain.delete_suffix('/').casecmp(Rails.configuration.x.local_domain).zero?
end
def normalize_domain(domain)
return if domain.nil?
uri = Addressable::URI.new
uri.host = domain.gsub(/[\/]/, '')
uri.host = domain.delete_suffix('/')
uri.normalized_host
end
@ -28,7 +28,7 @@ class TagManager
domain = uri.host + (uri.port ? ":#{uri.port}" : '')
TagManager.instance.web_domain?(domain)
rescue Addressable::URI::InvalidURIError
rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError
false
end
end

View file

@ -43,6 +43,9 @@ class VideoMetadataExtractor
@height = video_stream[:height]
@frame_rate = video_stream[:avg_frame_rate] == '0/0' ? nil : Rational(video_stream[:avg_frame_rate])
@r_frame_rate = video_stream[:r_frame_rate] == '0/0' ? nil : Rational(video_stream[:r_frame_rate])
# For some video streams the frame_rate reported by `ffprobe` will be 0/0, but for these streams we
# should use `r_frame_rate` instead. Video screencast generated by Gnome Screencast have this issue.
@frame_rate ||= @r_frame_rate
end
if (audio_stream = audio_streams.first)

View file

@ -140,6 +140,6 @@ class Admin::StatusBatchAction
end
def allowed_status_ids
AccountStatusesFilter.new(@report.target_account, current_account).results.with_discarded.where(id: status_ids).pluck(:id)
Admin::AccountStatusesFilter.new(@report.target_account, current_account).results.with_discarded.where(id: status_ids).pluck(:id)
end
end

View file

@ -354,13 +354,25 @@ class Status < ApplicationRecord
account_ids.uniq!
status_ids = cached_items.map { |item| item.reblog? ? item.reblog_of_id : item.id }.uniq
return if account_ids.empty?
accounts = Account.where(id: account_ids).includes(:account_stat, :user).index_by(&:id)
status_stats = StatusStat.where(status_id: status_ids).index_by(&:status_id)
cached_items.each do |item|
item.account = accounts[item.account_id]
item.reblog.account = accounts[item.reblog.account_id] if item.reblog?
if item.reblog?
status_stat = status_stats[item.reblog.id]
item.reblog.status_stat = status_stat if status_stat.present?
else
status_stat = status_stats[item.id]
item.status_stat = status_stat if status_stat.present?
end
end
end

View file

@ -12,7 +12,7 @@ class Admin::StatusPolicy < ApplicationPolicy
end
def show?
role.can?(:manage_reports, :manage_users) && (record.public_visibility? || record.unlisted_visibility? || record.reported?)
role.can?(:manage_reports, :manage_users) && (record.public_visibility? || record.unlisted_visibility? || record.reported? || viewable_through_normal_policy?)
end
def destroy?
@ -26,4 +26,10 @@ class Admin::StatusPolicy < ApplicationPolicy
def review?
role.can?(:manage_taxonomies)
end
private
def viewable_through_normal_policy?
StatusPolicy.new(current_account, record, @preloaded_relations).show?
end
end

View file

@ -8,6 +8,6 @@ class ActivityPub::FetchRemotePollService < BaseService
return unless supported_context?(json)
ActivityPub::ProcessStatusUpdateService.new.call(poll.status, json)
ActivityPub::ProcessStatusUpdateService.new.call(poll.status, json, json)
end
end

View file

@ -5,10 +5,11 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
include Redisable
include Lockable
def call(status, json, request_id: nil)
def call(status, activity_json, object_json, request_id: nil)
raise ArgumentError, 'Status has unsaved changes' if status.changed?
@json = json
@activity_json = activity_json
@json = object_json
@status_parser = ActivityPub::Parser::StatusParser.new(@json)
@uri = @status_parser.uri
@status = status
@ -308,6 +309,6 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
end
def forwarder
@forwarder ||= ActivityPub::Forwarder.new(@account, @json, @status)
@forwarder ||= ActivityPub::Forwarder.new(@account, @activity_json, @status)
end
end

View file

@ -12,7 +12,9 @@ class TranslateStatusService < BaseService
@content = status_content_format(@status)
@target_language = target_language
Rails.cache.fetch("translations/#{@status.language}/#{@target_language}/#{content_hash}", expires_in: CACHE_TTL) { translation_backend.translate(@content, @status.language, @target_language) }
Rails.cache.fetch("translations/#{@status.language}/#{@target_language}/#{content_hash}", expires_in: CACHE_TTL) do
Sanitize.fragment(translation_backend.translate(@content, @status.language, @target_language), Sanitize::Config::MASTODON_STRICT)
end
end
private

View file

@ -56,7 +56,7 @@ services:
web:
build: .
image: ghcr.io/mastodon/mastodon:v4.1.7
image: ghcr.io/mastodon/mastodon:v4.1.8
restart: always
env_file: .env.development
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -b 0.0.0.0 -p 3000"
@ -77,7 +77,7 @@ services:
streaming:
build: .
image: ghcr.io/mastodon/mastodon:v4.1.7
image: ghcr.io/mastodon/mastodon:v4.1.8
restart: always
env_file: .env.development
command: node ./streaming
@ -95,7 +95,7 @@ services:
sidekiq:
build: .
image: ghcr.io/mastodon/mastodon:v4.1.7
image: ghcr.io/mastodon/mastodon:v4.1.8
restart: always
env_file: .env.development
command: bundle exec sidekiq

View file

@ -13,7 +13,7 @@ module Mastodon
end
def patch
7
8
end
def flags

View file

@ -37,12 +37,14 @@ module Paperclip
@output_options['f'] = 'image2'
@output_options['vframes'] = 1
when 'mp4'
@output_options['acodec'] = 'aac'
@output_options['strict'] = 'experimental'
unless eligible_to_passthrough?(metadata)
@output_options['acodec'] = 'aac'
@output_options['strict'] = 'experimental'
if high_vfr?(metadata) && !eligible_to_passthrough?(metadata)
@output_options['vsync'] = 'vfr'
@output_options['r'] = @vfr_threshold
if high_vfr?(metadata)
@output_options['vsync'] = 'vfr'
@output_options['r'] = @vfr_threshold
end
end
end

View file

@ -40,24 +40,36 @@ describe Admin::StatusesController do
end
describe 'POST #batch' do
before do
post :batch, params: { account_id: account.id, action => '', admin_status_batch_action: { status_ids: status_ids } }
end
subject { post :batch, params: { :account_id => account.id, action => '', :admin_status_batch_action => { status_ids: status_ids } } }
let(:status_ids) { [media_attached_status.id] }
context 'when action is report' do
shared_examples 'when action is report' do
let(:action) { 'report' }
it 'creates a report' do
subject
report = Report.last
expect(report.target_account_id).to eq account.id
expect(report.status_ids).to eq status_ids
end
it 'redirects to report page' do
subject
expect(response).to redirect_to(admin_report_path(Report.last.id))
end
end
it_behaves_like 'when action is report'
context 'when the moderator is blocked by the author' do
before do
account.block!(user.account)
end
it_behaves_like 'when action is report'
end
end
end

View file

@ -13,12 +13,17 @@ RSpec.describe CacheConcern, type: :controller do
def empty_relation
render plain: cache_collection(Status.none, Status).size
end
def account_statuses_favourites
render plain: cache_collection(Status.where(account_id: params[:id]), Status).map(&:favourites_count)
end
end
before do
routes.draw do
get 'empty_array' => 'anonymous#empty_array'
post 'empty_relation' => 'anonymous#empty_relation'
get 'empty_array' => 'anonymous#empty_array'
get 'empty_relation' => 'anonymous#empty_relation'
get 'account_statuses_favourites' => 'anonymous#account_statuses_favourites'
end
end
@ -36,5 +41,20 @@ RSpec.describe CacheConcern, type: :controller do
expect(response.body).to eq '0'
end
end
context 'when given a collection of statuses' do
let!(:account) { Fabricate(:account) }
let!(:status) { Fabricate(:status, account: account) }
it 'correctly updates with new interactions' do
get :account_statuses_favourites, params: { id: account.id }
expect(response.body).to eq '[0]'
FavouriteService.new.call(account, status)
get :account_statuses_favourites, params: { id: account.id }
expect(response.body).to eq '[1]'
end
end
end
end

View file

@ -41,12 +41,12 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
describe '#call' do
it 'updates text' do
subject.call(status, json)
subject.call(status, json, json)
expect(status.reload.text).to eq 'Hello universe'
end
it 'updates content warning' do
subject.call(status, json)
subject.call(status, json, json)
expect(status.reload.spoiler_text).to eq 'Show more'
end
@ -64,7 +64,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'does not create any edits' do
@ -87,7 +87,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'does not create any edits' do
@ -135,7 +135,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'does not create any edits' do
@ -188,7 +188,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'does not create any edits' do
@ -216,11 +216,11 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
it 'does not create any edits' do
expect { subject.call(status, json) }.not_to change { status.reload.edits.pluck(&:id) }
expect { subject.call(status, json, json) }.to_not(change { status.reload.edits.pluck(&:id) })
end
it 'does not update the text, spoiler_text or edited_at' do
expect { subject.call(status, json) }.not_to change { s = status.reload; [s.text, s.spoiler_text, s.edited_at] }
expect { subject.call(status, json, json) }.to_not(change { s = status.reload; [s.text, s.spoiler_text, s.edited_at] })
end
end
@ -235,7 +235,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'does not create any edits' do
@ -259,7 +259,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
before do
status.update(ordered_media_attachment_ids: nil)
subject.call(status, json)
subject.call(status, json, json)
end
it 'does not create any edits' do
@ -273,7 +273,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
context 'originally without tags' do
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'updates tags' do
@ -299,7 +299,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'updates tags' do
@ -309,7 +309,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
context 'originally without mentions' do
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'updates mentions' do
@ -321,7 +321,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
let(:mentions) { [alice, bob] }
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'updates mentions' do
@ -332,7 +332,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
context 'originally without media attachments' do
before do
stub_request(:get, 'https://example.com/foo.png').to_return(body: attachment_fixture('emojo.png'))
subject.call(status, json)
subject.call(status, json, json)
end
let(:payload) do
@ -382,7 +382,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
before do
allow(RedownloadMediaWorker).to receive(:perform_async)
subject.call(status, json)
subject.call(status, json, json)
end
it 'updates the existing media attachment in-place' do
@ -410,7 +410,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
before do
poll = Fabricate(:poll, status: status)
status.update(preloadable_poll: poll)
subject.call(status, json)
subject.call(status, json, json)
end
it 'removes poll' do
@ -440,7 +440,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
before do
subject.call(status, json)
subject.call(status, json, json)
end
it 'creates a poll' do
@ -456,12 +456,12 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do
end
it 'creates edit history' do
subject.call(status, json)
subject.call(status, json, json)
expect(status.edits.reload.map(&:text)).to eq ['Hello world', 'Hello universe']
end
it 'sets edited timestamp' do
subject.call(status, json)
subject.call(status, json, json)
expect(status.reload.edited_at.to_s).to eq '2021-09-08 22:39:25 UTC'
end
end