This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
proposed @oelmekki @jpcyiza @tkuah @derekferguson 2023-09-12

ActivityPub 지원

요약

이 제안의 최종 목표는 GitLab에 상호 운용 가능한 기능을 구축하여 GitLab의 한 인스턴스에서 다른 인스턴스에 호스팅된 프로젝트로 Merge Request을 열 수 있도록 하여 전역 네트워크에서 모든 원하는 인스턴스를 Merge하는 것입니다.

이를 달성하기 위해 우리는 Fediverse에서 사용되는 w3c 표준인 ActivityPub을 사용하는 것을 제안합니다. 이를 통해 견고하고 검증된 프로토콜을 기반으로 구축할 수 있으며, GitLab을 보다 넓은 커뮤니티에 공개할 수 있을 것입니다.

크로스-인스턴스 Merge Request을 구현하기 전에, 우리는 더 작은 단계로 시작하여 ActivityPub에 대한 도메인 지식을 구축하고 더 고급 기능을 지원할 기반이 되는 하부 아키텍처를 만들 수 있도록 하고 싶습니다. 이를 위해 우리는 Fediverse의 사람들이 GitLab의 활동에 구독할 수 있도록 하는 사회 기능을 구현하는 것을 제안합니다. 예를 들어, GitLab에서 호스팅된 즐겨찾는 프로젝트가 새 릴리스를 만들 때 원하는 소셜 네트워크에서 알림을받을 수 있도록 합니다. 이는 GitLab을 더욱 사회적으로 만들고 사용자를 확보하는 기회가 될 것입니다.

관련 기술 및 용어 설명

동기부여로 이동 가능합니다.

ActivityPub

Fediverse 뒤에 서 있는 것은 ActivityPub 프로토콜입니다. 이것은 가능한 한 일반적인 소셜 네트워크 구현을 시도하는 HTTP API입니다.

기본 아이디어는 actoractivities를 보내고 받는다는 것입니다. 활동은 정의된 속성을 갖는 구조화된 JSON 메시지이지만, 어떤 필요도 커버할 수 있도록 확장 가능합니다. actor는 네 개의 엔드포인트로 정의되며, 이는 application/ld+json; profile="https://www.w3.org/ns/activitystreams" HTTP Accept 헤더를 사용하여 연락합니다:

  • GET /inbox: actor가 자신을 위해 새로운 활동을 찾는 데 사용됩니다.
  • ‘POST /inbox’: 인스턴스가 actor를 위해 새로운 활동을 푸시하는 데 사용됩니다.
  • GET /outbox: 누구나 actor가 생성 한 활동을 읽는 데 사용됩니다.
  • POST /outbox: actor가 새로운 활동을 게시하는 데 사용됩니다.

그 중 Mastodon과 Lemmy는 POST /inboxGET /outbox만 사용하며, 이는 연합을 구현하는 데 필요한 최소한으로 구현합니다.

또한, Mastodon과 Lemmy는 위에서 언급한 Accept 헤더를 사용하여 GET / 엔드포인트를 구현합니다. 이 엔드포인트는 actor에 대한 이름 및 URL과 같은 일반 정보로 응답합니다. 표준에 의해 필요한 것은 아니지만 검색이 쉬워집니다.

Fediverse

Mastodon과 Lemmy 뒤에 핵심 아이디어는 Fediverse입니다. 완전한 분산이 아니라 연합을 사용하여, 서버와 클라이언트가 여전히 존재한다는 점에서 분산화의 핵심 개념입니다. 사용자는 이 중 하나의 서버(인스턴스라고 함)에 가입하고, 그들은 그 서버(인스턴스)나 다른 서버(인스턴스)의 사용자와 상호 작용할 수 있습니다. 사용자의 관점에서 그들은 글로벌 네트워크를 볼 수 있으며, 자신의 인스턴스 뿐만 아니라 다른 인스턴스에서 게시된 기사를 볼 수 있으며, 댓글을 달 수 있고 추천할 수 있습니다.

Fediverse 뒤에서 일어나는 일: 사용자의 인스턴스는 그들이 회신하는 사용자가 호스팅되는 위치를 알고 있습니다. 다른 인스턴스에게 그들에게 메시지가 있다고 알리기 위해 그 다른 인스턴스와 연락을 취합니다. 또한 사용자가 피드를 구독할 때, 사용자의 인스턴스는 피드가 호스팅되는 인스턴스에게 여기에 대한 구독을 알립니다. 이 대상 인스턴스는 새로운 활동이 생성될 때 메시지를 다시 게시합니다. 이는 RSS와 달리 상시 폴 모델이 아닌 푸시 모델을 가능하게 합니다. 물론, 방금 설명한 것은 순조로운 길이며, 중간에서 모든 방향에서 모더레이션, 타당성 및 오류 허용이 발생합니다.

ActivityPub

Fediverse 뒤에는 ActivityPub 프로토콜이 있습니다. 이것은 가능한 한 일반적인 소셜 네트워크 구현을 시도하는 HTTP API입니다.

기본 아이디어는 actoractivities를 보내고 받는다는 것입니다. 활동은 정의된 속성을 갖는 구조화된 JSON 메시지이지만, 어떤 필요도 커버할 수 있도록 확장 가능합니다. actor는 네 개의 엔드포인트로 정의되며, 이는 application/ld+json; profile="https://www.w3.org/ns/activitystreams" HTTP Accept 헤더를 사용하여 연락합니다:

  • GET /inbox: actor가 자신을 위해 새로운 활동을 찾는 데 사용됩니다.
  • ‘POST /inbox’: 인스턴스가 actor를 위해 새로운 활동을 푸시하는 데 사용됩니다.
  • GET /outbox: 누구나 actor가 생성 한 활동을 읽는 데 사용됩니다.
  • POST /outbox: actor가 새로운 활동을 게시하는 데 사용됩니다.

이 중 Mastodon과 Lemmy는 POST /inboxGET /outbox만 사용하며, 이는 연합을 구현하는 데 필요한 최소한으로 구현합니다.

또한, Mastodon과 Lemmy는 위에서 언급한 Accept 헤더를 사용하여 GET / 엔드포인트를 구현합니다. 이 엔드포인트는 actor에 대한 이름 및 URL과 같은 일반 정보로 응답합니다. 표준에 의해 필요한 것은 아니지만 검색이 쉬워집니다.

활동이 주 목적인 actor에 사람이 주 사용 사례이지만, actor는 반드시 사람에 매핑되어야 하는 것은 아닙니다. 무엇이든 actor가 될 수 있습니다: 주제, 서브레딧, 그룹, 이벤트. GitLab의 경우 “activity”라는 용어의 의미에 따라 프로젝트, 그룹 및 릴리스와 같은 항목이 ActivityPub actor가 될 수 있습니다. 더 추상적인 예에서는 actor가 실행 가능한 피드로 생각될 수 있습니다.

ActivityPub 단독으로 Fediverse를 구현하는 데 필요한 모든 기능을 커버하지는 않습니다. 특히 구현자들에게 다음 사항을 해결하도록 남겨 두었습니다:

  • 스팸 처리 방법 찾기.
  • 새로운 인스턴스 발견.
  • 네트워크 전체 검색 수행.

동기부여

왜 소셜 미디어 프로토콜이 GitLab에 유용할까요? 사람들은 각 호스트에 등록하지 않고도 다양한 프로젝트 간에 상호 작용할 수 있는 단일 글로벌 GitLab 네트워크를 원합니다.

이미 매우 인기 있는 논의들 중 몇 가지는 이미 진행되었습니다:

이상적인 워크플로우는 다음과 같습니다:

  1. Alice는 gitlab.example.org와 같은 즐겨찾는 GitLab 인스턴스에 등록합니다.
  2. 그녀는 주제에 관한 프로젝트를 찾아보고, gitlab.com에 있는 Bob의 프로젝트를 볼 수 있습니다.
  3. Alice는 포크(Fork)를 선택하고, gitlab.com/Bob/project.gitgitlab.example.org/Alice/project.git로 포크됩니다.
  4. 그녀는 자신의 편집을 하고, Bob의 프로젝트인 gitlab.com에서 통합 요청을 엽니다.
  5. Alice와 Bob은 각각의 GitLab 인스턴스에서 통합 요청에 대해 논의합니다.
  6. Bob은 Alice의 인스턴스에서 회신된 추가 커밋을 보낼 수 있습니다.
  7. Bob이 통합 요청을 수락하면, 그의 인스턴스가 Alice의 인스턴스에서 코드를 가져갑니다.

이 프로세스에서 ActivityPub은 다음과 같은 점에서 도움이됩니다:

  • Bob에게 포크가 발생했음을 알립니다.
  • 통합 요청을 Bob에게 보냅니다.
  • Alice와 Bob이 통합 요청에 대해 논의할 수 있도록 합니다.
  • Alice에게 코드가 Merge되었음을 알려줍니다.

특정 구현이 필요한 이러한 경우에는 도움이되지 않지만, 여기에는 특정 구현이 필요합니다:

  • 네트워크 전체 검색 구현.
  • 크로스-인스턴스 포크 구현 (Git 덕분에 필요 없음).

여기서 ActivityPub을 사용하는 이유는 특정 방식으로 크로스-인스턴스 Merge Request을 구현하는 대신에 표준의 기반 위에 구축하는 것이 두 가지 이유가 있습니다:

  1. 표준을 기반으로 구축하면 GitLab 이상으로 도달하는 데 도움이 됩니다. 위에서 제시된 워크플로우는 GitLab만 언급하지만, W3C 표준을 기반으로 구축하는 것은 다른 대포들이 GitLab을 따라갈 수 있도록 해주고 코드 공유의 대규모 Fediverse를 구축할 수 있습니다.
  2. GitLab을 더 사회적으로 만들 수 있는 기회가 됩니다. 위에서 제시한 워크플로우를 위한 아키텍처를 준비하기 위해, 사람들이 자신의 Fediverse 소셜 네트워크에서 활동 피드를 구독할 수 있는 허용할 수 있는 보다 작은 단계를 밟을 수 있습니다. RSS 피드가있는 모든 것을 ActivityPub 피드로 전환할 수 있습니다. Mastodon의 사람들은 GitLab의 즐겨찾는 개발자, 프로젝트 또는 주제를 팔로우하고 그 뉴스를 자신의 Mastodon 피드에서 볼 수 있으며, 이는 GitLab과의 참여 확대를 기대할 수 있는 희망적인 결과입니다.

목표

  • ActivityPub 기반 소셜 미디어에서 흥미로운 이벤트를 공유할 수 있도록 함
  • 한 인스턴스에서 이슈를 열고 다른 인스턴스로 논의할 수 있도록 함
  • 한 인스턴스에서 프로젝트를 포크하고 다른 인스턴스로 이동할 수 있도록 함
  • 한 인스턴스에서 Merge Request을 열고 논의하며 다른 인스턴스로 Merge할 수 있도록 함
  • 네트워크 전체 검색을 수행할 수 있도록 함

비목표

  • 비공개 리소스 연합
  • 네트워크 전체 검색 수행을 허용할 수 있는지?

제안

이 구현 경로의 아이디어는 가장 가치 있는 기능(인스턴스간 Merge Request)으로 가는 가장 빠른 경로를 취하는 것이 아니라, 각 반복에서 가장 작지만 유용한 단계로 진행하여 각 단계가 즉시 유용한 기능을 제공함을 확실히 하는 것입니다.

  1. 소셜 팔로우를 위한 ActivityPub 구현. 이 후 Fediverse는 GitLab 인스턴스에서의 활동을 팔로우할 수 있습니다.
    1. ActivityPub을 사용하여 프로젝트 릴리스를 구독합니다.
    2. ActivityPub을 사용하여 주제에 새 프로젝트를 구독합니다.
    3. ActivityPub을 사용하여 프로젝트 활동을 구독합니다.
    4. ActivityPub을 사용하여 그룹 활동을 구독합니다.
    5. ActivityPub을 사용하여 사용자 활동을 구독합니다.
  2. 인스턴스간 포크를 구현하여 한 인스턴스에서 프로젝트를 포크할 수 있도록 함.
  3. 다른 인스턴스에서의 토론을 위한 ActivityPub 구현을 구현하여 다른 인스턴스에서의 이슈 및 Merge Request 논의를 가능하게 함:
    1. 이슈에서.
    2. Merge Request에서.
  4. 인스턴스 간 Merge Request을 제출하기 위한 ActivityPub 구현을 구현하여 다른 인스턴스로 Merge Request을 제출할 수 있도록 함.
  5. 인스턴스 간 검색을 구현하여 다른 인스턴스의 프로젝트를 발견할 수 있도록 함.

이 마지막 단계가 모두 포함되어야 하는지 논의의 여지가 있습니다. 현재 대부분의 Fediverse 앱에서는 인스턴스가 알지 못하는 리소스(일반적으로 따르고 싶은 사용자)를 표시하려고 할 때 자신의 인스턴스에서 리소스의 URL을 검색 상자에 붙여 넣으면 원격 리소스를 검색하여 표시하고 이제 자신의 인스턴스에서 조치를 취할 수 있습니다. 우리는 먼저 그것을 계획하고 있습니다.

그 질문은: 우리는 그만으로 유지할까요? 이 UX는 특히 Fediverse UX 패턴에 익숙하지 않은 사용자들에게 심각한 마찰이 있습니다(아마도 대부분의 GitLab 사용자들은 그렇습니다). 반면에 분산 검색은 자체 청사진을 받을만큼 복잡한 주제이기 때문에 별도의 청사진을 받을만큼 복잡한 주제이기 때문에, 이제는 분산 프로토콜 및 응용 프로그램이 그것에 대해 작업했기 때문에 예전만큼 복잡하지는 않습니다.

설계 및 구현 세부 사항

먼저, 우리가 사용할 세 가지 표준 사양에 익숙해지는 것이 좋습니다:

  • ActivityPub은 연합을 구현하는데 일어나는 HTTP 요청을 정의합니다.
  • ActivityStreams은 프로토콜 사용자들에 의해 교환되는 JSON 메시지의 형식을 정의합니다.
  • Activity 어휘는 기본적으로 인식되는 다양한 메시지를 정의합니다.

문서가 너무 밀도가 높다고 생각되면 @oelmekki에게 질문해도 좋습니다.

제품 준비 상태

TBC

소셜 팔로우 부분

이 부분은 GitLab에 새로운 ActivityPub 액터를 추가하여 기초 작업을 하는 것입니다.

구현하고 싶은 5개의 액터가 있습니다:

  • 릴리스 액터, 특정 프로젝트가 새 릴리스를 만들 때 알림을 받을 수 있게 하는 것
  • 주제 액터, 주제에 새로운 프로젝트가 추가될 때 알림을 받을 수 있게 하는 것
  • 프로젝트 액터, 프로젝트로부터의 모든 활동과 관련이 있는 액터
  • 그룹 액터, 그룹으로부터의 모든 활동과 관련이 있는 액터
  • 사용자 액터, 사용자로부터의 모든 활동과 관련이 있는 액터

우리는 현재 공개 리소스만 다루고 있습니다. 비공개 리소스 연합을 허용하는 것은 나중에 해결해야 할 까다로운 주제이며, 가능한 경우입니다.

엔드포인트

각 액터에는 3개의 엔드포인트가 필요합니다:

  • 기본 정보, 즉 이름, 설명뿐 아니라 인박스와 아웃박스에 대한 링크를 포함하는 프로필 엔드포인트
  • 액터의 이전 활동을 보여주는 아웃박스 엔드포인트
  • 팔로우 및 언팔로우 요청을 게시하기 위한 인박스 엔드포인트(현재 사용하지 않는 기타 사항을 포함합니다).

이러한 엔드포인트를 제공하는 컨트롤러들은 app/controllers/activity_pub/에 있습니다. 이 네임스페이스를 사용하여 ActivityPub JSON 응답을 프론트엔드용 응답과 혼동하지 않도록 하고, 나중에 우리의 다음 인스턴스 간 기능을 위해 형식화하는 방법이 다를 수 있기 때문에 나중에 추가적인 네임스페이스가 필요할 수 있기 때문에 이 네임스페이스를 사용하여 우리가 필요로 하는 것을 쉽게 토글할 수 있습니다. 또한, 이 네임스페이스는 모든 엔드포인트에서 필요한 것을 쉽게 토글할 수 있도록 하고, 예를 들어 특정 프로젝트에 대해 액세스할 수 없도록 하는 등의 기능을 제공합니다.

직렬화기

app/serializers/activity_pub/의 직렬화기는 ActivityStreams 객체를 제공함으로써 우리의 구현의 핵심입니다. 추상 클래스 ActivityPub::ActivityStreamsSerializer는 개발자가 제공한 데이터를 유효성 검사하고 공통 필드를 설정하며 페이지네이션을 제공하는 중요한 작업을 수행합니다.

이 페이지네이션 부분은 Gitlab::Serializer::Pagination을 통해 오프셋 페이지네이션을 사용합니다. 키셋 페이지네이션을 수행할 수 있도록 하기 있어야 합니다.

구독

리소스에 대한 구독은 팔로우 활동을 액터 인박스에 게시함으로써 이루어집니다. 팔로우 활동을 받으면 반환될 수 있는 Accept 또는 Reject 활동을 생성해야 합니다.

구현의 일반적인 워크플로우는 다음과 같습니다:

  • 팔로우 활동이 JSON으로 인코딩되어 인박스 엔드포인트에 POST 요청을 수행함
  • 활동이 지원되는 유형이 아닌 경우(예: 누군가가 활동에 댓글을 남기려고 시도할 때) 무시합니다. 그렇지 않은 경우:
  • 우리는 가입자의 프로필 URL로 ActivityPub::Subscription를 생성합니다.
  • 우리는 가입자의 인박스 URL을 해결하기 위해 작업을 큐에 등록합니다.
    • 가입자의 프로필에 HTTP 요청을 수행하여 가입자의 인박스 URL(그리고 공유 인박스 URL이 있는 경우)을 찾습니다.
    • 그 URL을 구독 레코드에 저장합니다.
  • 구독을 수락하기 위해 작업을 큐에 등록합니다.
    • 가입자의 인박스로 Accept 활동을 게시하기 위해 가입자의 인박스에 HTTP 요청을 수행합니다.
    • 구독의 상태를 :accepted로 업데이트합니다.

ActivityPub::Subscription은 새로운 추상 모델이며, 여기서 각각의 테이블을 가지고 있는 우리의 액터와 관련된 모델들을 상속받습니다:

  • ActivityPub::ReleasesSubscription, 테이블 activity_pub_releases_subscriptions
  • ActivityPub::TopicSubscription, 테이블 activity_pub_topic_subscriptions
  • ActivityPub::ProjectSubscription, 테이블 activity_pub_project_subscriptions
  • ActivityPub::GroupSubscription, 테이블 activity_pub_group_subscriptions
  • ActivityPub::UserSubscription, 테이블 activity_pub_user_subscriptions

하나의 테이블에 단일 테이블에 단순히 actor 열거형을 사용하는 대신(예: 프로젝트에는 ActivityPub::ProjectSubscription이 속하고 사용자에는 ActivityPub::UserSubscription이 속하지 않습니다) 이유는 각각의 특정 연합을 위한 특정 연관 및 유효성 검사가 필요하기 때문입니다. 또한 추후 확장성에 대한 더 많은 여지를 제공합니다.

언팔로우

이전 팔로우를 언급하는 Undo 활동을 받으면 디비에서 구독을 제거합니다.

우리는 다른 활동을 보낼 의무가 없으므로 여기에 어떤 워커도 필요하지 않으며, 직접적으로 디비에서 레코드를 삭제할 수 있습니다.

활동 전송

특정 이벤트(어떤 것인가?)가 액터와 관련된 경우, 구독자의 인박스에 활동을 발행하는 이벤트를 큐에 등록해야 합니다(활동은 액터의 아웃박스에 표시하는 것과 동일합니다).

확실히 동일한 사람에게 두 번 활동을 보내지 않도록 구독자 디렉터리을 그룹화해야 합니다. 활동을 수신할 때 중복성을 처리하는 것은 아마도 클라이언트의 활동 받을 때 유일성 유효성 검사에 의해 더 잘 처리되어야 할 것입니다.

더 중요한 것은 같은 호스트에 대한 요청을 그룹화해야 합니다. 예를 들어, 열 명의 사용자가 모두 https://mastodon.social/에 있으면 공유된 인박스에 대해 단일 요청을 제공하여 추가할 수 있습니다. 사용자당 하나의 요청을 보내는 대신 모든 사용자에 대해 단일 요청을 보내는 것이 더 나을 수 있습니다.

Webfinger

Mastodon은 인스턴스가 Webfinger 프로토콜을 구현해야 함을 필요로 합니다. 이 프로토콜은 잘 알려진 위치에 엔드포인트를 추가하여 리소스 이름을 쿼리하고 원하는 URL로 매핑할 수 있게 해주는 것에 관한 것입니다 (기본적으로 발견용으로 사용됨). Mastodon은 이를 사용하여 엑터 이름에 대해 다른 페디버스 앱에 쿼리하여 그들의 프로필 URL을 찾습니다.

실제로 GitLab은 이미 Doorkeeper를 통해 Webfinger 프로토콜 엔드포인트를 구현합니다(이것이 해당 라우트에 매핑되는 동작입니다), JwksController에 구현됨(https://gitlab.com/gitlab-org/gitlab/-/blob/efa76816bd0603ba3acdb8a0f92f54abfbf5cc02/app/controllers/jwks_controller.rb).

여기서는 호환성 문제가 없습니다. 우리는 단지 이 컨트롤러를 확장하면 됩니다. 그러나, 아마도 Jwks와 더는 관련이 없으므로 이름을 바꿔야 할 것입니다.

우리가 가질 수 있는 한 가지 어려움은 Mastodon과는 달리 사용자뿐만 아니라 프로젝트도 처리한다는 것입니다. 따라서 사용자에게 문의하는 것과 프로젝트에 대한 문의를 구별할 수 있는 방법을 찾아야 합니다. 하나 사실 관례적인 방법은 user-<username>, project-<project_name>과 같이 접두사를 사용하는 것입니다. 이 형식은 멀리서 고려 중이며, 우리가 이 큰 이슈에 대한 코드를 아직 구현하지 않았기 때문에 그리 심도있게 Webfinger의 사양을 파헤치지 않았기 때문에 실제 구현에 도달할 때 이는 폐기될 수 있습니다.

HTTP signatures

Mastodon은 HTTP 서명을 필요로 합니다, 이것은 주어진 서버를 가장하는 스패머가 시도하지 않도록 하는 또 다른 표준입니다.

이는 SSH나 PGP와 같이 개인 키와 공개 키로 이루어진 비대칭 암호화입니다. 우리는 요청에 서명하는 것과 그것들을 검증하는 것을 둘 다 구현해야 할 것입니다. 이것은 나중에 큰 이슈에서 다양한 GitLab 인스턴스 간에 통신하고 싶을 때 상당한 도움이 될 것입니다.

호스트 허용디렉터리과 거부디렉터리

GitLab 인스턴스 소유자가 잠재적인 스패머 제어를 할 수 있게 하기 위해 두 가지 상호 배타적인 호스트 디렉터리을 유지할 수 있어야 합니다:

  • 허용디렉터리: 이 디렉터리에 언급된 호스트만 페더레이션될 수 있음.
  • 거부디렉터리: 이 디렉터리에 언급된 호스트를 제외하고 모든 호스트가 페더레이션될 수 있음.

설정은 소유자가 허용디렉터리과 거부디렉터리 사이를 전환할 수 있도록 해야 합니다. 처음에는 Rails 콘솔에서 관리할 수 있겠지만, 최종적으로는 관리자 인터페이스에 섹션을 추가해야 할 것입니다.

제한과 롤아웃

첫 달에 기능을 출시할 때 부하를 제어하기 위해, gitlab.com에서는 허용디렉터리을 사용하도록 설정하고, Fediverse 서버를 한 번에 몇 개씩 롤아웃하여 점차적으로 부하를 관찰한 후에 거부디렉터리으로 전환할 것입니다(참고: 현재 gitlab.com에서 페더레이션을 활성화해야 하는지 여부에 대한 진행 중인 토론이 있음).

또한 페더레이션이 남용되지 않도록 제한을 구현해야 합니다.

  • 리소스가 받을 수 있는 구독 수를 제한함.
  • 타사 서버가 생성할 수 있는 구독 수를 제한함.

인스턴스 간 문제 및 Merge Request 부분

우리는 소셜 팔로잉 부분을 설계하기 전에 ActivityPub에 대한 경험을 쌓기 위해 이 부분을 설계할 때까지 기다릴 것입니다.