git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 04/18] t1401-symbolic-ref: avoid direct filesystem access

From
SZEDER Gábor <szeder.dev@gmail.com>
Date
Apr 23, 2021, 05:12 UTC
Message-ID
<20210423051255.GD2947267@szeder.dev>
In-Reply-To
<CAFQ2z_Md=LAkJzohf3E5ogWGQHzxN_ik=yHAGmxm7bg-yT6-Zw@mail.gmail.com>
On Thu, Apr 22, 2021 at 03:01:01PM +0200, Han-Wen Nienhuys wrote:
Show 22 quoted lines
> On Thu, Apr 22, 2021 at 6:59 AM SZEDER Gábor <szeder.dev@gmail.com> wrote:
> > > See the comment above the changed line: we don't want auto-detection
> > > to clobber the surrounding git repo.
> >
> > Indeed, but then this is not a faithful conversion of the original.
> > That 'echo' will write sane content to HEAD no matter what state the
> > repository is in.  That 'symbolic-ref' command, however, won't,
> > because 'git --git-dir .git' turns off only repository discovery, but
> > not repository verification, and in case of a corrupt '.git/HEAD' it
> > will bail out.
> >
> >   $ cd test
> >   $ git init
> >   Initialized empty Git repository in /home/szeder/src/git/test/.git/
> >   $ git commit --allow-empty -m initial
> >   [master (root-commit) ec0df0b] initial
> >   $ echo "foo bar baz" >.git/HEAD
> >   $ git --git-dir .git symbolic-ref HEAD refs/heads/master
> >   fatal: not a git repository: '.git'
> 
> But then it's working as intended, no? It will not corrupt the
> surrounding repository.
No, it definitely does not.

If one of the test cases fails because 'git symbolic-ref' were to write bogus content to HEAD, then that new 'git symbolic-ref' invocation in reset_to_sane() will not corrupt the surrounding repository, but, crucially, it won't restore the test repository's HEAD to a sane state either, and git commands invoked in subsequent tests won't recognize the trash dir as their git repository, and will operate on the surrounding repo instead:

  ~/src/git/t (master)$ vim t/t1401-symbolic-ref.sh
  ~/src/git/t (master *)$ git diff
  diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
  index a4ebb0b65f..8f8d93bf6a 100755
  --- a/t/t1401-symbolic-ref.sh
  +++ b/t/t1401-symbolic-ref.sh
  @@ -23,7 +23,11 @@ test_expect_success 'symbolic-ref reads HEAD' '
   '
   
   test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
  -       test_must_fail git symbolic-ref HEAD foo
  +       #test_must_fail git symbolic-ref HEAD foo &&
  +       # Lets pretend that the above "git symbolic-ref" did write that
  +       # bogus content to HEAD:
  +       echo foo >.git/HEAD &&
  +       false
   '
   reset_to_sane
   
  ~/src/git/t (master *)$ ./t1401-symbolic-ref.sh 
  ok 1 - symbolic-ref writes HEAD
  ok 2 - symbolic-ref reads HEAD
  not ok 3 - symbolic-ref refuses non-ref for HEAD
  #	
  #		#test_must_fail git symbolic-ref HEAD foo &&
  #		# Lets pretend that the above "git symbolic-ref" did write that
  #		# bogus content to HEAD:
  #		echo foo >.git/HEAD &&
  #		false
  #	
  ok 4 - symbolic-ref refuses bare sha1
  ok 5 - HEAD cannot be removed
  ok 6 - symbolic-ref can be deleted
  ok 7 - symbolic-ref can delete dangling symref
  ok 8 - symbolic-ref fails to delete missing FOO
  ok 9 - symbolic-ref fails to delete real ref
  ok 10 - create large ref name
  ok 11 - symbolic-ref can point to large ref name
  ok 12 - we can parse long symbolic ref
  ok 13 - symbolic-ref reports failure in exit code
  ok 14 - symbolic-ref writes reflog entry
  ok 15 - symbolic-ref does not create ref d/f conflicts
  ok 16 - symbolic-ref can overwrite pointer to invalid name
  ok 17 - symbolic-ref can resolve d/f name (EISDIR)
  ok 18 - symbolic-ref can resolve d/f name (ENOTDIR)
  # failed 1 among 18 test(s)
  1..18
  ~/src/git/t (master *)$
OK, only one test failed, and the surrounding repo is not affected.
No lets switch to your 'git symbolic-ref command in reset_to_sane():
  ~/src/git/t (master *)$ vim t/t1401-symbolic-ref.sh
  ~/src/git/t (master *)$ git diff
  diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
  index a4ebb0b65f..6ef221d1bb 100755
  --- a/t/t1401-symbolic-ref.sh
  +++ b/t/t1401-symbolic-ref.sh
  @@ -7,7 +7,8 @@ test_description='basic symbolic-ref tests'
   # the git repo, meaning that further tests will operate on
   # the surrounding git repo instead of the trash directory.
   reset_to_sane() {
  -       echo ref: refs/heads/foo >.git/HEAD
  +       #echo ref: refs/heads/foo >.git/HEAD
  +       git --git-dir .git symbolic-ref HEAD refs/heads/foo
   }
   
   test_expect_success 'symbolic-ref writes HEAD' '
  @@ -23,7 +24,11 @@ test_expect_success 'symbolic-ref reads HEAD' '
   '
   
   test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
  -       test_must_fail git symbolic-ref HEAD foo
  +       #test_must_fail git symbolic-ref HEAD foo &&
  +       # Lets pretend that the above "git symbolic-ref" did write that
  +       # bogus content to HEAD:
  +       echo foo >.git/HEAD &&
  +       false
   '
   reset_to_sane
 
  ~/src/git/t (master *)$ ./t1401-symbolic-ref.sh 
  ok 1 - symbolic-ref writes HEAD
  ok 2 - symbolic-ref reads HEAD
  not ok 3 - symbolic-ref refuses non-ref for HEAD
  #	
  #		#test_must_fail git symbolic-ref HEAD foo &&
  #		# Lets pretend that the above "git symbolic-ref" did write that
  #		# bogus content to HEAD:
  #		echo foo >.git/HEAD &&
  #		false
  #	
  fatal: not a git repository: '.git'
  not ok 4 - symbolic-ref refuses bare sha1
  #	
  #		echo content >file && git add file && git commit -m one &&
  #		test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)
  #	
  fatal: not a git repository: '.git'
  ok 5 - HEAD cannot be removed
  fatal: not a git repository: '.git'
  not ok 6 - symbolic-ref can be deleted
  #	
  #		git symbolic-ref NOTHEAD refs/heads/foo &&
  #		git symbolic-ref -d NOTHEAD &&
  #		test_path_is_file .git/refs/heads/foo &&
  #		test_path_is_missing .git/NOTHEAD
  #	
  fatal: not a git repository: '.git'
  ok 7 - symbolic-ref can delete dangling symref
  fatal: not a git repository: '.git'
  ok 8 - symbolic-ref fails to delete missing FOO
  fatal: not a git repository: '.git'
  not ok 9 - symbolic-ref fails to delete real ref
  #	
  #		echo "fatal: Cannot delete refs/heads/foo, not a symbolic ref" >expect &&
  #		test_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 &&
  #		git rev-parse --verify refs/heads/foo &&
  #		test_cmp expect actual
  #	
  fatal: not a git repository: '.git'
  ok 10 - create large ref name
  ok 11 - symbolic-ref can point to large ref name
  ok 12 - we can parse long symbolic ref
  not ok 13 - symbolic-ref reports failure in exit code
  #	
  #		test_when_finished "rm -f .git/HEAD.lock" &&
  #		>.git/HEAD.lock &&
  #		test_must_fail git symbolic-ref HEAD refs/heads/whatever
  #	
  not ok 14 - symbolic-ref writes reflog entry
  #	
  #		git checkout -b log1 &&
  #		test_commit one &&
  #		git checkout -b log2  &&
  #		test_commit two &&
  #		git checkout --orphan orphan &&
  #		git symbolic-ref -m create HEAD refs/heads/log1 &&
  #		git symbolic-ref -m update HEAD refs/heads/log2 &&
  #		cat >expect <<-\EOF &&
  #		update
  #		create
  #		EOF
  #		git log --format=%gs -g -2 >actual &&
  #		test_cmp expect actual
  #	
  not ok 15 - symbolic-ref does not create ref d/f conflicts
  #	
  #		git checkout -b df &&
  #		test_commit df &&
  #		test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df &&
  #		git pack-refs --all --prune &&
  #		test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df
  #	
  not ok 16 - symbolic-ref can overwrite pointer to invalid name
  #	
  #		test_when_finished reset_to_sane &&
  #		head=$(git rev-parse HEAD) &&
  #		git symbolic-ref HEAD refs/heads/outer &&
  #		test_when_finished "git update-ref -d refs/heads/outer/inner" &&
  #		git update-ref refs/heads/outer/inner $head &&
  #		git symbolic-ref HEAD refs/heads/unrelated
  #	
  not ok 17 - symbolic-ref can resolve d/f name (EISDIR)
  #	
  #		test_when_finished reset_to_sane &&
  #		head=$(git rev-parse HEAD) &&
  #		git symbolic-ref HEAD refs/heads/outer/inner &&
  #		test_when_finished "git update-ref -d refs/heads/outer" &&
  #		git update-ref refs/heads/outer $head &&
  #		echo refs/heads/outer/inner >expect &&
  #		git symbolic-ref HEAD >actual &&
  #		test_cmp expect actual
  #	
  not ok 18 - symbolic-ref can resolve d/f name (ENOTDIR)
  #	
  #		test_when_finished reset_to_sane &&
  #		head=$(git rev-parse HEAD) &&
  #		git symbolic-ref HEAD refs/heads/outer &&
  #		test_when_finished "git update-ref -d refs/heads/outer/inner" &&
  #		git update-ref refs/heads/outer/inner $head &&
  #		echo refs/heads/outer >expect &&
  #		git symbolic-ref HEAD >actual &&
  #		test_cmp expect actual
  #	
  # failed 10 among 18 test(s)
  1..18

Uh-oh, a lot more tests failes, and, much worse!, my git repo is now on a different and orphaned branch:

  ~/src/git/t (df *+)$ git status 
  On branch df
  
  No commits yet
  
  Changes to be committed:
  [...]
> I see it as the test writer's job to clean up to the extent that
> git-symbolic-ref can reset to a sane state.

No, it's the job of whoever updates the cleanup routine to make sure that the updated cleanup routine still works just as well as it did in the past.

> We could reset back to a known state in a more drastic manner
> (extracting .git from a tar archive), but that could interfere with
> the test functions if they're not isolated from each other.
Previous: Han-Wen NienhuysNext: Han-Wen Nienhuys
Message 15 of 138 in “Prepare tests for reftable backend”
  1. 00/18 Prepare tests for reftable backendHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  2. 01/18 t4202: split testcase for invalid HEAD symref and HEAD hashHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  3. SZEDER GáborApr 19, 2021
  4. Han-Wen NienhuysApr 27, 2021
  5. 05/18 t1413: use tar to save and restore entire .git directoryHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  6. Junio C HamanoApr 20, 2021
  7. Han-Wen NienhuysApr 27, 2021
  8. 04/18 t1401-symbolic-ref: avoid direct filesystem accessHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  9. SZEDER GáborApr 19, 2021
  10. Han-Wen NienhuysApr 27, 2021
  11. Ævar Arnfjörð BjarmasonApr 21, 2021
  12. Han-Wen NienhuysApr 21, 2021
  13. SZEDER GáborApr 22, 2021
  14. Han-Wen NienhuysApr 22, 2021
  15. SZEDER GáborApr 23, 2021
  16. Han-Wen NienhuysApr 23, 2021
  17. Han-Wen NienhuysApr 23, 2021
  18. Ævar Arnfjörð BjarmasonApr 23, 2021
  19. Han-Wen NienhuysApr 26, 2021
  20. 03/18 t5601: read HEAD using rev-parseHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  21. 06/18 t1301: fix typo in error messageHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  22. 02/18 t9300: check ref existence using git-rev-parse rather than FS checkHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  23. Ævar Arnfjörð BjarmasonApr 21, 2021
  24. Han-Wen NienhuysApr 27, 2021
  25. 07/18 t5000: inspect HEAD using git-rev-parseHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  26. Ævar Arnfjörð BjarmasonApr 21, 2021
  27. Han-Wen NienhuysApr 27, 2021
  28. 09/18 t5304: use "reflog expire --all" to clear the reflogHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  29. Ævar Arnfjörð BjarmasonApr 21, 2021
  30. Han-Wen NienhuysApr 27, 2021
  31. 08/18 t7003: use rev-parse rather than FS inspectionHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  32. 10/18 test-lib: provide test prereq REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  33. Junio C HamanoApr 20, 2021
  34. Junio C HamanoApr 20, 2021
  35. Han-Wen NienhuysApr 26, 2021
  36. Han-Wen NienhuysApr 27, 2021
  37. 12/18 t1414: mark corruption test with REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  38. 11/18 t1407: require REFFILES for for_each_reflog testHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  39. Ævar Arnfjörð BjarmasonApr 21, 2021
  40. Han-Wen NienhuysApr 27, 2021
  41. 13/18 t2017: mark --orphan/logAllRefUpdates=false test as REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  42. Ævar Arnfjörð BjarmasonApr 21, 2021
  43. Han-Wen NienhuysApr 29, 2021
  44. 15/18 t7900: mark pack-refs tests as REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  45. Ævar Arnfjörð BjarmasonApr 21, 2021
  46. Han-Wen NienhuysApr 27, 2021
  47. 16/18 t7003: check reflog existence only for REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  48. Junio C HamanoApr 20, 2021
  49. Han-Wen NienhuysApr 26, 2021
  50. Han-Wen NienhuysApr 27, 2021
  51. Ævar Arnfjörð BjarmasonApr 21, 2021
  52. 14/18 t1404: mark tests that muck with .git directly as REFFILES.Han-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  53. Ævar Arnfjörð BjarmasonApr 21, 2021
  54. Han-Wen NienhuysApr 26, 2021
  55. 17/18 t4202: mark bogus head hash test with REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  56. Ævar Arnfjörð BjarmasonApr 21, 2021
  57. Han-Wen NienhuysApr 26, 2021
  58. 18/18 t1415: set REFFILES for test specific to storage formatHan-Wen Nienhuys via GitGitGadget, Apr 19, 2021
  59. Ævar Arnfjörð BjarmasonApr 21, 2021
  60. Han-Wen NienhuysApr 26, 2021
  61. 00/21 Prepare tests for reftable backendHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  62. 04/21 t5601: read HEAD using rev-parseHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  63. 01/21 t4202: split testcase for invalid HEAD symref and HEAD hashHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  64. Ævar Arnfjörð BjarmasonMay 20, 2021
  65. Han-Wen NienhuysMay 31, 2021
  66. 06/21 t1413: use tar to save and restore entire .git directoryHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  67. Ævar Arnfjörð BjarmasonMay 20, 2021
  68. Han-Wen NienhuysMay 31, 2021
  69. 05/21 t1401-symbolic-ref: avoid direct filesystem accessHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  70. Ævar Arnfjörð BjarmasonMay 20, 2021
  71. Han-Wen NienhuysMay 31, 2021
  72. 02/21 t/helper/ref-store: initialize oid in resolve-refHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  73. Ævar Arnfjörð BjarmasonMay 20, 2021
  74. Han-Wen NienhuysMay 31, 2021
  75. 03/21 t9300: check ref existence using test-helper rather than a file system checkHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  76. Ævar Arnfjörð BjarmasonMay 20, 2021
  77. 08/21 t5000: reformat indentation to the latest fashionHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  78. Ævar Arnfjörð BjarmasonMay 20, 2021
  79. Han-Wen NienhuysMay 31, 2021
  80. 09/21 t5000: inspect HEAD using git-rev-parseHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  81. 07/21 t1301: fix typo in error messageHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  82. 11/21 t5304: restyle: trim empty lines, drop ':' before >Han-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  83. 10/21 t7003: use rev-parse rather than FS inspectionHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  84. 12/21 t5304: use "reflog expire --all" to clear the reflogHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  85. Ævar Arnfjörð BjarmasonMay 20, 2021
  86. Han-Wen NienhuysMay 31, 2021
  87. 18/21 t7900: mark pack-refs tests as REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  88. Ævar Arnfjörð BjarmasonMay 20, 2021
  89. Han-Wen NienhuysMay 31, 2021
  90. 14/21 t1407: require REFFILES for for_each_reflog testHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  91. 13/21 test-lib: provide test prereq REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  92. 15/21 t1414: mark corruption test with REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  93. Ævar Arnfjörð BjarmasonMay 20, 2021
  94. 19/21 t7003: check reflog existence only for REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  95. Ævar Arnfjörð BjarmasonMay 20, 2021
  96. Han-Wen NienhuysMay 31, 2021
  97. 16/21 t2017: mark --orphan/logAllRefUpdates=false test as REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  98. Ævar Arnfjörð BjarmasonMay 20, 2021
  99. 17/21 t1404: mark tests that muck with .git directly as REFFILES.Han-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  100. 21/21 t1415: set REFFILES for test specific to storage formatHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  101. Ævar Arnfjörð BjarmasonMay 20, 2021
  102. Han-Wen NienhuysMay 31, 2021
  103. Ævar Arnfjörð BjarmasonMay 31, 2021
  104. 20/21 t4202: mark bogus head hash test with REFFILESHan-Wen Nienhuys via GitGitGadget, Apr 27, 2021
  105. Ævar Arnfjörð BjarmasonMay 20, 2021
  106. Han-Wen NienhuysMay 31, 2021
  107. Ævar Arnfjörð BjarmasonMay 20, 2021
  108. Han-Wen NienhuysMay 26, 2021
  109. Ævar Arnfjörð BjarmasonMay 26, 2021
  110. Han-Wen NienhuysMay 31, 2021
  111. 00/22 Prepare tests for reftable backendHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  112. 02/22 t/helper/ref-store: initialize oid in resolve-refHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  113. 01/22 t4202: split testcase for invalid HEAD symref and HEAD hashHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  114. 04/22 t5601: read HEAD using rev-parseHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  115. 03/22 t9300: check ref existence using test-helper rather than a file system checkHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  116. 05/22 t1401: use tar to snapshot and restore repo stateHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  117. 07/22 t1413: use tar to save and restore entire .git directoryHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  118. Bagas SanjayaJun 1, 2021
  119. Han-Wen NienhuysJun 1, 2021
  120. Junio C HamanoJun 1, 2021
  121. Han-Wen NienhuysJun 2, 2021
  122. 06/22 t1401-symbolic-ref: avoid direct filesystem accessHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  123. 08/22 t1301: fix typo in error messageHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  124. 09/22 t5000: reformat indentation to the latest fashionHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  125. 10/22 t5000: inspect HEAD using git-rev-parseHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  126. 11/22 t7003: use rev-parse rather than FS inspectionHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  127. 12/22 t5304: restyle: trim empty lines, drop ':' before >Han-Wen Nienhuys via GitGitGadget, May 31, 2021
  128. 15/22 t1407: require REFFILES for for_each_reflog testHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  129. 17/22 t2017: mark --orphan/logAllRefUpdates=false test as REFFILESHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  130. 14/22 test-lib: provide test prereq REFFILESHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  131. 18/22 t1404: mark tests that muck with .git directly as REFFILES.Han-Wen Nienhuys via GitGitGadget, May 31, 2021
  132. 16/22 t1414: mark corruption test with REFFILESHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  133. 21/22 t4202: mark bogus head hash test with REFFILESHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  134. 13/22 t5304: use "reflog expire --all" to clear the reflogHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  135. 19/22 t7900: stop checking for loose refsHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  136. 20/22 t7003: check reflog existence only for REFFILESHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  137. 22/22 t1415: set REFFILES for test specific to storage formatHan-Wen Nienhuys via GitGitGadget, May 31, 2021
  138. Ævar Arnfjörð BjarmasonMay 31, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.